├── .gitignore ├── README.markdown ├── TabletMagic.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── common ├── Constants.h ├── Wacom.h └── wactablet.h ├── daemon ├── Daemon_Prefix.pch ├── SerialDaemon.cpp ├── SerialDaemon.h ├── TMSerialPort.cpp ├── TMSerialPort.h ├── TabletSettings.cpp └── TabletSettings.h ├── helper ├── Digitizers.c ├── Digitizers.h └── LaunchHelper.c ├── prefpane ├── English.lproj │ ├── InfoPlist.strings │ ├── Localizable.strings │ ├── TabletMagicPref.xib │ └── TabletMagicSearchGroups.searchTerms ├── Info.plist ├── Resources │ ├── PrefPaneTitle.png │ ├── TabletMagicPref.tiff │ ├── TabletMagicStarter │ │ ├── Resources │ │ │ ├── Dutch.lproj │ │ │ │ └── Localizable.strings │ │ │ ├── English.lproj │ │ │ │ └── Localizable.strings │ │ │ ├── French.lproj │ │ │ │ └── Localizable.strings │ │ │ ├── German.lproj │ │ │ │ └── Localizable.strings │ │ │ ├── Italian.lproj │ │ │ │ └── Localizable.strings │ │ │ ├── Japanese.lproj │ │ │ │ └── Localizable.strings │ │ │ └── Spanish.lproj │ │ │ │ └── Localizable.strings │ │ ├── StartupParameters.plist │ │ └── TabletMagic │ ├── TabletPCEnabler.sh │ ├── button.jpg │ ├── trigger-off.png │ └── trigger-on.png ├── TMAreaChooser.h ├── TMAreaChooser.m ├── TMAreaChooserScreen.h ├── TMAreaChooserScreen.m ├── TMAreaChooserTablet.h ├── TMAreaChooserTablet.m ├── TMController.h ├── TMController.m ├── TMPreset.h ├── TMPreset.m ├── TMPresetsController.h ├── TMPresetsController.m ├── TMScratchpad.h ├── TMScratchpad.m ├── TabletMagicPref.h ├── TabletMagicPref.m ├── TabletMagic_Prefix.pch ├── fr.lproj │ ├── InfoPlist.strings │ ├── Localizable.strings │ ├── TabletMagicPref.xib │ └── TabletMagicSearchGroups.searchTerms ├── include │ ├── GetPID.c │ └── GetPID.h └── it.lproj │ ├── InfoPlist.strings │ ├── Localizable.strings │ ├── TabletMagicPref.xib │ └── TabletMagicSearchGroups.searchTerms └── version.plist /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.xcscheme 3 | *.perspective 4 | *.pbxuser 5 | *.xcbkptlist 6 | *.mode1v3 7 | xcschememanagement.plist 8 | UserInterfaceState.xcuserstate 9 | build 10 | TabletMagic.xcodeproj/project.xcworkspace/xcuserdata/lordscott.xcuserdatad/WorkspaceSettings.xcsettings 11 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | TabletMagic Links 2 | ----------------- 3 | - [TabletMagic Home](http://www.thinkyhead.com/tabletmagic) 4 | - [Thinkyhead Software](http://www.thinkyhead.com/) 5 | - [TabletMagic for TabletPC](http://www.insanelymac.com/forum/topic/43948-tabletmagic-for-tabletpcs/) 6 | - [USB Serial Adapters](http://www.thinkyhead.com/tabletmagic/adapters) 7 | 8 | What Is TabletMagic? 9 | -------------------- 10 | _TabletMagic_ is an OS X driver for obsolete serial Wacom tablets. The minimum system requirement is Mac OS X 10.4. A USB to serial adapter will also be required. 11 | 12 | TabletMagic also works as a driver for TabletPC digitizers based on Wacom serial hardware. TabletPCs with "ISD-V4" or "Fujitsu P-series" protocol are currently supported. [This Page](http://www.insanelymac.com/forum/topic/43948-tabletmagic-for-tabletpcs/) contains more information and help for TabletPC users. 13 | 14 | Installation 15 | ------------ 16 | Double-click the control panel to install it. The panel will install the other components when you start the daemon for the first time. If you want the daemon to start automatically when you boot the computer, you need to check the `Launch at Startup` option in the `Extras` tab. 17 | 18 | Installed Components 19 | -------------------- 20 | - "TabletMagicDaemon" is the actual device driver that communicates with the tablet and produces Mac system events. The daemon is a relatively simple C++ project. There's a class to represent the tablet, one for the serial port interface, and a small class to encapsulate UD-style tablet parameters. The intra-application messaging interface is part of the tablet class, but this will be placed in its own class pretty soon. 21 | 22 | - "LaunchHelper" is a simple C program that the TabletMagic preference pane uses to perform any actions that require escalated privileges. The preference pane asks for an admin password on first-run and tells LaunchHelper to suid itself. From then on no password is required. 23 | 24 | - The "TabletMagic" preference pane is an Objective-C / Cocoa plugin that provides a user interface to start, stop, and configure TabletMagic. It is currently localized in English, French, and Italian. 25 | 26 | Notes 27 | ----- 28 | Some kinds of drivers –USB for example– need to run in the kernel, but TabletMagic doesn't require a kernel extension. The daemon can freely run in user space without any of the other components present. 29 | 30 | TabletMagic uses CFMessagePort for messaging between the daemon and preference pane. However, the prefpane and daemon run in different "bootstrap domains" when the daemon is auto-started. Although the daemon can receive messages from the preference pane as soon as they are sent, the preference pane must use synchronous messaging and poll for any messages sent by the daemon. Presumably this could be worked around with Unix domain sockets, but I've had no luck so far in that approach. 31 | 32 | The code is probably fine in terms of efficiency, but it could use an overhaul in terms of standards, encapsulation, and doxygen comments. 33 | 34 | Troubleshooting 35 | --------------- 36 | For users with _USB Serial Adapters_ the most common problem is the driver, so make sure to use the latest drivers available for your hardware variety. USB Serial Adapters are pretty generic, so usually the chip maker's reference driver will work even if the branded driver doesn't. See the [TabletMagic Serial Adapters Page](http://www.thinkyhead.com/tabletmagic/adapters) for more links and information. 37 | -------------------------------------------------------------------------------- /TabletMagic.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /common/Constants.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Constants.h 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | #ifndef CONSTANTS_H 9 | #define CONSTANTS_H 10 | 11 | #define TABLETMAGIC_VERSION "2.0.0" 12 | 13 | #define ASYNCHRONOUS_MESSAGING 0 14 | #define FORCE_TABLETPC 0 15 | 16 | #define KNOWN_DIGIS {"WAC","FUJ","FPI"} 17 | 18 | enum { 19 | kStylusTip = 0, 20 | kStylusButton1, 21 | kStylusButton2, 22 | kStylusEraser, 23 | kStylusButtonTypes, 24 | 25 | kButtonLeft, // Mouse button 1 26 | kButtonMiddle, // Mouse button 3 27 | kButtonRight, // Mouse button 2 28 | kButtonExtra, // Mouse button 4 29 | kButtonSide, // Mouse Button 5 30 | kButtonMax, 31 | 32 | kSystemNoButton = 0, 33 | kSystemButton1, 34 | kSystemButton2, 35 | kSystemButton3, 36 | kSystemButton4, 37 | kSystemButton5, 38 | kSystemEraser, 39 | kSystemDoubleClick, 40 | kSystemSingleClick, 41 | kSystemControlClick, 42 | kSystemClickOrRelease, 43 | kSystemClickTypes, 44 | 45 | kOtherButton3 = 2, 46 | kOtherButton4, 47 | kOtherButton5, 48 | 49 | kBitStylusTip = 1 << kStylusTip, 50 | kBitStylusButton1 = 1 << kStylusButton1, 51 | kBitStylusButton2 = 1 << kStylusButton2, 52 | kBitStylusEraser = 1 << kStylusEraser, 53 | 54 | k12inches1270ppi = 15240 55 | }; 56 | 57 | 58 | #pragma mark - 59 | 60 | // 61 | // TabletPC Command Strings 62 | // 63 | #define TPC_StopTablet "0" 64 | #define TPC_Sample133pps "1" 65 | #define TPC_Sample80pps "2" 66 | #define TPC_Sample40pps "3" 67 | #define TPC_SurveyScanOn "+" 68 | #define TPC_SurveyScanOff "-" 69 | #define TPC_TabletID "*" 70 | 71 | 72 | #pragma mark - 73 | 74 | // 75 | // Wacom Tablet Command Strings 76 | // 77 | #define WAC_StartTablet "ST\r" 78 | #define WAC_StopTablet "SP\r" 79 | #define WAC_SelfTest "TE\r" 80 | #define WAC_TabletID "~#\r" 81 | #define WAC_TabletSize "~C\r" 82 | #define WAC_ReadSetting "~R\r" 83 | #define WAC_ReadSettingM1 "~R1\r" 84 | #define WAC_ReadSettingM2 "~R2\r" 85 | 86 | // Commands unavailable on CT 87 | #define WAC_ResetBitpad2 "%%" 88 | #define WAC_ResetMM1201 "&&" 89 | #define WAC_ResetWacomII "\r$" 90 | #define WAC_ResetWacomIV "\r#" 91 | #define WAC_ResetDefaults "RE\r" 92 | #define WAC_TiltModeOn "FM1\r" 93 | #define WAC_TiltModeOff "FM0\r" 94 | #define WAC_MultiModeOn "MU1\r" 95 | #define WAC_MultiModeOff "MU0\r" 96 | #define WAC_SuppressIN2 "SU2\r" 97 | #define WAC_PointMode "PO\r" 98 | #define WAC_SwitchStreamMode "SW\r" 99 | #define WAC_StreamMode "SR\r" 100 | #define WAC_DataContinuous "AL1\r" 101 | #define WAC_DataTrailing "AL2\r" 102 | #define WAC_DataNormal "AL0\r" 103 | #define WAC_OriginUL "OC1\r" 104 | #define WAC_OriginLL "OC0\r" 105 | 106 | // Numerical settings 107 | #define WAC_IntervalOff "IT0\r" 108 | #define WAC_IncrementOff "IN0\r" 109 | 110 | // Wacom II-S Commands 111 | #define WAC_PressureModeOn "PH1\r" 112 | #define WAC_PressureModeOff "PH0\r" 113 | #define WAC_ASCIIMode "AS0\r" 114 | #define WAC_BinaryMode "AS1\r" 115 | #define WAC_RelativeModeOn "DE1\r" 116 | #define WAC_RelativeModeOff "DE0\r" 117 | #define WAC_Rez1000ppi "IC1\r" 118 | #define WAC_Rez50ppmm "IC0\r" 119 | 120 | // Macro button commands 121 | #define WAC_MacroAll "~M0\r" 122 | #define WAC_MacroNoSetup "~M1\r" 123 | #define WAC_MacroNoFunction "~M2\r" 124 | #define WAC_MacroNoPressure "~M3\r" 125 | #define WAC_MacroExtended "~M4\r" 126 | 127 | // Prefixes for longer commands 128 | #define WAC_NewResolution "NR" 129 | #define WAC_Suppress "SU" 130 | 131 | 132 | #pragma mark - 133 | 134 | // 135 | // Wacom V Command Strings 136 | // 137 | #define WACV_MultiModeOff "MT0\r" 138 | #define WACV_MultiModeOn "MT1\r" 139 | #define WACV_Height "HT1\r" 140 | #define WACV_TabletID "ID1\r" 141 | #define WACV_SetBaud19200 "BA19\r" 142 | #define WACV_SetBaud9600 "$\r" 143 | #define WACV_SetBaud38400 "BA38\r" 144 | 145 | 146 | #pragma mark - 147 | 148 | // 149 | // CalComp Tablet Command Strings 150 | // 151 | #define CAL_ "\x1B%" 152 | #define CAL_StartTablet CAL_ "IR\r" 153 | #define CAL_StopTablet CAL_ "H\r" 154 | #define CAL_TabletID CAL_ "__p\r" 155 | #define CAL_Version CAL_ "__V\r" 156 | #define CAL_TabletSize CAL_ "VS\r" 157 | #define CAL_OriginUL CAL_ "JUL\r" 158 | #define CAL_OriginLL CAL_ "JLL\r" 159 | #define CAL_PressureModeOn CAL_ "VA1\r" 160 | #define CAL_PressureModeOff CAL_ "VA0\r" 161 | #define CAL_TilttoPressureOn CAL_ "VA3\r" 162 | #define CAL_TilttoPressureOff CAL_ "VA2\r" 163 | #define CAL_ASCIIMode CAL_ "^17\r" 164 | #define CAL_BinaryMode CAL_ "^21\r" 165 | #define CAL_22Mode CAL_ "^22\r" 166 | #define CAL_Rez1000ppi CAL_ "JR1000,0\r" 167 | #define CAL_Rez1270ppi CAL_ "JR1270,0\r" 168 | #define CAL_Rez2540ppi CAL_ "JR2540,0\r" 169 | #define CAL_Rez50ppmm CAL_ "JM50,0\r" 170 | #define CAL_ReadSetting CAL_ "^17\r" 171 | #define CAL_Reset CAL_ "VR\r" 172 | #define CAL_StreamMode CAL_ "IR\r" 173 | #define CAL_Rez1000ppi CAL_ "JR1000,0\r" 174 | #define CAL_DataRate1 CAL_ "W1\r" 175 | #define CAL_DataRate50 CAL_ "W50\r" 176 | #define CAL_DataRate125 CAL_ "W125\r" 177 | #define CAL_LFEnable CAL_ "L1\r" 178 | #define CAL_LFDisable CAL_ "L0\r" 179 | 180 | 181 | #pragma mark - Main Preference Keys 182 | 183 | #define keyTabletEnabled @"tabletEnabled" 184 | #define keySerialPort @"serialPort" 185 | #define keySelectedTab @"selectedTab" 186 | #define keyPenColor @"penColor" 187 | #define keyEraserColor @"eraserColor" 188 | #define keyPresets @"presets" 189 | #define keyIDonated @"iDonatedV214" 190 | #define keyTabletPC @"tabletPC" 191 | #define keyTabletPCScaleX @"tabletPCScaleX" 192 | #define keyTabletPCScaleY @"tabletPCScaleY" 193 | #define keyDidFixButtons @"didFixButtons" 194 | 195 | 196 | // These are remembered and used as a default state 197 | // for either a running daemon or a non-running one 198 | // 199 | // TODO: Make sure the daemon initializes the serial port 200 | // to the visible settings after these are set from prefs 201 | // 202 | #define keySerialBaudRate @"serialBaudRate" 203 | #define keySerialDataBits @"serialDataBits" 204 | #define keySerialParity @"serialParity" 205 | #define keySerialStopBits @"serialStopBits" 206 | #define keySerialCTS @"serialCTS" 207 | #define keySerialDSR @"serialDSR" 208 | 209 | #pragma mark - Preset Preference Keys 210 | 211 | // Presets and their properties 212 | #define keyPresetList @"presetList" 213 | #define keySelectedPreset @"selectedPreset" 214 | 215 | #define keyName "name" 216 | #define keyTabletRangeX "tabletRangeX" 217 | #define keyTabletRangeY "tabletRangeY" 218 | #define keyTabletLeft "tabletLeft" 219 | #define keyTabletTop "tabletTop" 220 | #define keyTabletRight "tabletRight" 221 | #define keyTabletBottom "tabletBottom" 222 | #define keyScreenWidth "screenWidth" 223 | #define keyScreenHeight "screenHeight" 224 | #define keyScreenLeft "screenLeft" 225 | #define keyScreenTop "screenTop" 226 | #define keyScreenRight "screenRight" 227 | #define keyScreenBottom "screenBottom" 228 | #define keyStylusTip "stylusTip" 229 | #define keySwitch1 "switch1" 230 | #define keySwitch2 "switch2" 231 | #define keyEraser "eraser" 232 | #define keyMouseMode "mouseMode" 233 | #define keyMouseScaling "mouseScaling" 234 | #define keyConstrained "constrained" 235 | 236 | #pragma mark - 237 | 238 | // Tablet model letters for comparison 239 | #define kTabletModelUnknown "Unknown" 240 | #define kTabletModelIntuos2 "XD" 241 | #define kTabletModelIntuos "GD" 242 | #define kTabletModelGraphire3 "CTE" 243 | #define kTabletModelGraphire2 "ETA" 244 | #define kTabletModelGraphire "ET" 245 | #define kTabletModelCintiq "PL" 246 | #define kTabletModelCintiqPartner "PTU" 247 | #define kTabletModelArtZ "UD" 248 | #define kTabletModelArtPad "KT" 249 | #define kTabletModelPenPartner "CT" 250 | #define kTabletModelSDSeries "SD" 251 | #define kTabletModelTabletPC "ISD" 252 | #define kTabletModelCalComp "Cal" 253 | 254 | // Included for completeness 255 | #define kTabletModelPLSeries "PL" 256 | #define kTabletModelUDSeries "UD" 257 | 258 | // Numeric index for each model 259 | enum SeriesIndex { 260 | kModelUnknown = 0, 261 | kModelIntuos2 , 262 | kModelIntuos , 263 | kModelGraphire3 , 264 | kModelGraphire2 , 265 | kModelGraphire , 266 | kModelCintiq , 267 | kModelCintiqPartner , 268 | kModelArtZ , 269 | kModelArtPad , 270 | kModelPenPartner , 271 | kModelSDSeries , 272 | kModelTabletPC , 273 | kModelFujitsuP , 274 | kModelCalComp , 275 | 276 | // Included for completeness 277 | kModelPLSeries , 278 | kModelUDSeries 279 | }; 280 | 281 | // Tablet setup bitfields 282 | enum { 283 | kCommandSetBitpadII = 0, 284 | kCommandSetMM1201 = 1, 285 | kCommandSetWacomIIS = 2, 286 | kCommandSetWacomIV = 3, 287 | kCommandSetWacomV = 4, // Synthetic - looks like BitPadII to prefs 288 | kCommandSetTabletPC = 5, // Synthetic - looks like MM1201 to prefs 289 | 290 | kBaudRate2400 = 0, 291 | kBaudRate4800 = 1, 292 | kBaudRate9600 = 2, 293 | kBaudRate19200 = 3, 294 | kBaudRate38400 = 4, // Synthetic - looks like 2400 to prefs 295 | 296 | kParityNone = 0, 297 | kParityNone2 = 1, 298 | kParityOdd = 2, 299 | kParityEven = 3, 300 | 301 | kDataBits7 = 0, 302 | kDataBits8 = 1, 303 | 304 | kStopBits1 = 0, 305 | kStopBits2 = 1, 306 | 307 | kCTSDisabled = 0, 308 | kCTSEnabled = 1, 309 | 310 | kDSRDisabled = 0, 311 | kDSREnabled = 1, 312 | 313 | kTransferModeSuppressed = 0, 314 | kTransferModePoint = 1, 315 | kTransferModeSwitchStream = 2, 316 | kTransferModeStream = 3, 317 | 318 | kOutputFormatBinary = 0, 319 | kOutputFormatASCII = 1, 320 | 321 | kCoordSysAbsolute = 0, 322 | kCoordSysRelative = 1, 323 | 324 | kTransferRate50pps = 0, 325 | kTransferRate67pps = 1, 326 | kTransferRate100pps = 2, 327 | kTransferRateMAX = 3, 328 | kTransferRate200pps = 4, // Synthetic 329 | 330 | kResolution500lpi = 0, 331 | kResolution508lpi = 1, 332 | kResolution1000lpi = 2, 333 | kResolution1270lpi = 3, 334 | kResolution2540lpi = 4, // Synthetic 335 | 336 | kOriginUL = 0, 337 | kOriginLL = 1, 338 | 339 | kOORDisabled = 0, 340 | kOOREnabled = 1, 341 | 342 | kTerminatorCR = 0, 343 | kTerminatorLF = 1, 344 | kTerminatorCRLF = 2, 345 | kTerminatorCRLF2 = 3, 346 | 347 | kPNPDisabled = 0, 348 | kPNPEnabled = 1, 349 | 350 | kSensitivityFirm = 0, 351 | kSensitivitySoft = 1, 352 | 353 | kReadHeight8mm = 0, 354 | kReadHeight2mm = 1, 355 | 356 | kMDMDisabled = 0, 357 | kMDMEnabled = 1, 358 | 359 | kTiltDisabled = 0, 360 | kTiltEnabled = 1, 361 | 362 | kMMCommandSet1201 = 0, 363 | kMMCommandSet961 = 1, 364 | 365 | kOrientationLandscape = 0, 366 | kOrientationPortrait = 1, 367 | 368 | kCursorData1234 = 0, 369 | kCursorData1248 = 1, 370 | 371 | kRemoteModeDisabled = 0, 372 | kRemoteModeEnabled = 1 373 | }; 374 | 375 | // 376 | // Tablet packet bit masks 377 | // 378 | 379 | // Wacom V 380 | #pragma mark - Wacom V 381 | 382 | #define V_Mask1_ToolHi 0x7F 383 | #define V_Mask2_ToolLo 0x7C 384 | 385 | #define V_Mask2_Serial 0x03 386 | #define V_Mask3_Serial 0x7F 387 | #define V_Mask4_Serial 0x7F 388 | #define V_Mask5_Serial 0x7F 389 | #define V_Mask6_Serial 0x7F 390 | #define V_Mask7_Serial 0x60 391 | 392 | #define V_Mask1_X 0x7F 393 | #define V_Mask2_X 0x7F 394 | #define V_Mask3_X 0x60 395 | #define V_Mask3_Y 0x1F 396 | #define V_Mask4_Y 0x7F 397 | #define V_Mask5_Y 0x78 398 | 399 | #define V_Mask7_TiltX 0x3F 400 | #define V_Mask7_TiltXBase 0x40 401 | #define V_Mask8_TiltY 0x3F 402 | #define V_Mask8_TiltYBase 0x40 403 | 404 | #define V_Mask5_PressureHi 0x07 405 | #define V_Mask6_PressureLo 0x7F 406 | 407 | #define V_Mask0_Button1 0x02 408 | #define V_Mask0_Button2 0x04 409 | 410 | #define V_Mask5_WheelHi 0x07 411 | #define V_Mask6_WheelLo 0x7F 412 | 413 | #define V_Mask5_ThrottleHi 0x07 414 | #define V_Mask6_ThrottleLo 0x7F 415 | #define V_Mask8_ThrottleSign 0x08 416 | 417 | #define V_Mask6_4dRotationHi 0x0F 418 | #define V_Mask7_4dRotationLo 0x7F 419 | #define V_Mask8_4dButtonsHi 0x70 420 | #define V_Mask8_4dButtonsLo 0x07 421 | 422 | #define V_Mask8_LensButtons 0x1F 423 | 424 | #define V_Mask8_2dButtons 0x1C 425 | 426 | #define V_Mask8_WheelUp 0x02 427 | #define V_Mask8_WheelDown 0x01 428 | 429 | // Wacom IV 430 | #pragma mark - Wacom IV 431 | 432 | #define IV_Mask0_Engagement 0x60 433 | #define IV_DisengagedOrMenu 0x20 434 | 435 | #define IV_Mask0_Stylus 0x20 436 | 437 | #define IV_Mask0_ButtonFlag 0x08 438 | 439 | #define IV_Mask0_X 0x03 440 | #define IV_Mask1_X 0x7F 441 | #define IV_Mask2_X 0x7F 442 | 443 | #define IV_Mask3_Buttons 0x78 444 | #define IV_Mask3_Pressure0 0x04 445 | 446 | #define IV_Mask3_Y 0x03 447 | #define IV_Mask4_Y 0x7F 448 | #define IV_Mask5_Y 0x7F 449 | 450 | #define IV_Mask7_TiltX 0x3F 451 | #define IV_Mask7_TiltXBase 0x40 452 | #define IV_Mask8_TiltY 0x3F 453 | #define IV_Mask8_TiltYBase 0x40 454 | 455 | #define IV_Mask6_PressureLo 0x3F 456 | #define IV_Mask6_PressureHi 0x40 457 | 458 | // Wacom II-S 459 | #pragma mark - Wacom II-S 460 | 461 | #define IIs_Mask0_Proximity 0x40 462 | #define IIs_Mask0_Pressure 0x10 463 | #define IIs_Mask0_Engaged 0x60 464 | #define IIs_Disengaged 0x20 465 | 466 | #define IIs_Mask0_X 0x03 467 | #define IIs_Mask1_X 0x7F 468 | #define IIs_Mask2_X 0x7F 469 | 470 | #define IIs_Mask3_Y 0x03 471 | #define IIs_Mask4_Y 0x7F 472 | #define IIs_Mask5_Y 0x7F 473 | 474 | #define IIs_Mask6_EraserOrTip 0x01 475 | #define IIs_Mask6_Button1 0x02 476 | #define IIs_Mask6_EraserOr2 0x04 477 | #define IIs_Mask6_PressureLo 0x3F 478 | #define IIs_Mask6_PressureHi 0x40 479 | #define IIs_Mask6_ButtonFlag 0x20 480 | 481 | // CalComp 482 | #pragma mark - CalComp 483 | #define CAL_Mask0_Proximity 0x40 484 | #define CAL_Mask0_Buttons 0x7C 485 | #define CAL_Mask0_Pressure 0x10 486 | #define CAL_Mask0_Engaged 0x60 487 | #define CAL_Mask0_CursorOrPen 0x40 488 | #define CAL_Mask0_Stylus 0x04 489 | #define CAL_Mask0_Pen1 0x08 490 | #define CAL_Mask0_Pen2 0x10 491 | #define CAL_Mask0_Button1 0x04 492 | #define CAL_Mask0_Button2 0x08 493 | #define CAL_Mask0_Eraser 0x10 494 | #define CAL_Disengaged 0x20 495 | 496 | #define CAL_Mask0_X 0x03 497 | #define CAL_Mask1_X 0x7F 498 | #define CAL_Mask2_X 0x7F 499 | #define CAL_Mask3_X 0x18 500 | 501 | #define CAL_Mask3_Y 0x07 502 | #define CAL_Mask4_Y 0x7F 503 | #define CAL_Mask5_Y 0x7F 504 | 505 | #define CAL_Mask6_EraserOrTip 0x01 506 | #define CAL_Mask6_Button1 0x02 507 | #define CAL_Mask6_Button2 0x04 508 | #define CAL_Mask6_EraserOr2 0x08 509 | #define CAL_Mask6_Pressure 0xFF 510 | #define CAL_Mask6_ButtonFlag 0x20 511 | 512 | // Wacom SD420L 513 | #pragma mark - SD Series 514 | 515 | #define SD_Mask0_Pressure 0x10 516 | #define SD_Mask6_PressureLo 0x3F 517 | #define SD_Mask6_PressureHi 0x40 518 | 519 | // TabletPC 520 | #pragma mark - TabletPC 521 | 522 | #define TPC_Mask0_QueryData 0x40 523 | 524 | #define TPC_Mask0_Proximity 0x20 525 | #define TPC_Mask0_Eraser 0x04 526 | 527 | #define TPC_Mask0_Touch 0x01 528 | #define TPC_Mask0_Switch1 0x02 529 | #define TPC_Mask0_Switch2 0x04 530 | 531 | #define TPC_Mask6_PressureHi 0x01 532 | #define TPC_Mask5_PressureLo 0x7F 533 | 534 | #define TPC_Mask6_X 0x60 535 | #define TPC_Mask2_X 0x7F 536 | #define TPC_Mask1_X 0x7F 537 | 538 | #define TPC_Mask6_Y 0x18 539 | #define TPC_Mask4_Y 0x7F 540 | #define TPC_Mask3_Y 0x7F 541 | 542 | // TabletPC Query Data 543 | #pragma mark - TabletPC Query Data 544 | 545 | #define TPC_QUERY_REPLY_SIZE 11 546 | 547 | #define TPC_Query0_Data 0x3F 548 | 549 | #define TPC_Query6_PressureHi 0x07 550 | #define TPC_Query5_PressureLo 0x7F 551 | 552 | #define TPC_Query6_MaxX 0x60 553 | #define TPC_Query2_MaxX 0x7F 554 | #define TPC_Query1_MaxX 0x7F 555 | 556 | #define TPC_Query6_MaxY 0x18 557 | #define TPC_Query4_MaxY 0x7F 558 | #define TPC_Query3_MaxY 0x7F 559 | 560 | #define TPC_Query9_FirmwareHi 0x7F 561 | #define TPC_Query10_FirmwareLo 0x7F 562 | 563 | 564 | #pragma mark - 565 | 566 | #define NSBOOL(x) [NSNumber numberWithBool:(x)] 567 | #define NSINT(x) [NSNumber numberWithInt:(x)] 568 | #define NSFLOAT(x) [NSNumber numberWithFloat:(x)] 569 | 570 | #define BIT(x) (1<<(x)) 571 | #define clearstr(x) x[0]='\0' 572 | 573 | #endif 574 | -------------------------------------------------------------------------------- /common/Wacom.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------- 2 | 3 | NAME 4 | 5 | Wacom.h -- your basic useful enums and defines 6 | 7 | See CarbonEvents.h for definitions of the tablet event structs. 8 | 9 | COPYRIGHT 10 | 11 | Copyright WACOM Technologies, Inc. 2001 12 | All rights reserved. 13 | 14 | -----------------------------------------------------------------------------*/ 15 | 16 | typedef enum EPointerType 17 | { 18 | EUnknown = 0, // should never happen 19 | EPen, // tip end of a stylus like device 20 | ECursor, // any puck like device 21 | EEraser // eraser end of a stylus like device 22 | } EPointerType; 23 | 24 | 25 | // capabilities masks 26 | // Use these masks with the capabilities field of a proximity 27 | // event to determine what fields in a Tablet Event are valid 28 | // for this device. 29 | #define kTransducerDeviceIdBitMask 0x0001 30 | #define kTransducerAbsXBitMask 0x0002 31 | #define kTransducerAbsYBitMask 0x0004 32 | #define kTransducerVendor1BitMask 0x0008 33 | #define kTransducerVendor2BitMask 0x0010 34 | #define kTransducerVendor3BitMask 0x0020 35 | #define kTransducerButtonsBitMask 0x0040 36 | #define kTransducerTiltXBitMask 0x0080 37 | #define kTransducerTiltYBitMask 0x0100 38 | #define kTransducerAbsZBitMask 0x0200 39 | #define kTransducerPressureBitMask 0x0400 40 | #define kTransducerTangentialPressureBitMask 0x0800 41 | #define kTransducerOrientInfoBitMask 0x1000 42 | #define kTransducerRotationBitMask 0x2000 43 | 44 | 45 | 46 | /***************************************************************************** 47 | * The following is a list of the old capability masks constant names and a 48 | * description of what has happened to them. 49 | * Some of them have only changed in name, and not in value and are listed as 50 | * a #defined to the new name. 51 | * 52 | * 53 | ****************************************************************************** 54 | */ 55 | 56 | //#define kTransducerContextIdBitMask kTransducerDeviceIdBitMask 57 | 58 | // kTransducerContextStatusBitMask 59 | // This mask had no relevence to the Tablet Event structure and should not be used. 60 | // The old value of this mask is now used by kTransducerAbsXBitMask 61 | 62 | // kTransducerTimeStampBitMask 63 | // This mask had no relevence to the Tablet Event structure and should not be used. 64 | // The old value of this mask is now used by kTransducerAbsYBitMask 65 | 66 | // kTransducerItemsChangedBitMask 67 | // This mask had no relevence to the Tablet Event structure and should not be used. 68 | // The old value of this mask is now used by kTransducerVendor1BitMask 69 | 70 | // kTransducerPacketSerialNumBitMask 71 | // This mask had no relevence to the Tablet Event structure and should not be used. 72 | // The old value of this mask is now used by kTransducerVendor2BitMask 73 | 74 | // kTransducerCursorIndexBitMask 75 | // This mask had no relevence to the Tablet Event structure and should not be used. 76 | // The old value of this mask is now used by kTransducerVendor3BitMask 77 | 78 | // kTransducerXAxisBitMask 79 | // The value of this mask has changed to kTransducerAbsXBitMask 80 | // The old value is now used by kTransducerTiltXBitMask 81 | 82 | // kTransducerYAxisBitMask 83 | // The value of this mask has changed to kTransducerAbsYBitMask 84 | // The old value is now used by kTransducerTiltYBitMask 85 | 86 | // kTransducerOrientInfoBitMask 87 | // You really should start using kTransducerTiltXBitMask & kTransducerTiltXBitMask 88 | // However kTransducerOrientInfoBitMask does still exist with the same value so that 89 | // already shipping applications will still work. 90 | 91 | 92 | //#define kTransducerButtonStatesBitMask kTransducerButtonsBitMaskk 93 | //#define kTransducerZAxisBitMask kTransducerAbsZBitMask 94 | //#define kTransducerTipPressureBitMask kTransducerPressureBitMask 95 | //#define kTransducerBarrelPressureBitMask kTransducerTangentialPressureBitMask 96 | -------------------------------------------------------------------------------- /common/wactablet.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | ** wactablet.h 3 | ** 4 | ** Copyright (C) 2002,2003 - John E. Joganic 5 | ** 6 | ** This program is free software; you can redistribute it and/or 7 | ** modify it under the terms of the GNU General Public License 8 | ** as published by the Free Software Foundation; either version 2 9 | ** of the License, or (at your option) any later version. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU Lesser General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef __LINUXWACOM_WACTABLET_H 23 | #define __LINUXWACOM_WACTABLET_H 24 | 25 | #include 26 | #include 27 | 28 | #define WACOMVENDOR_UNKNOWN 0x0000 29 | #define WACOMVENDOR_WACOM 0x056A 30 | #define WACOMVENDOR_ACER 0xFFFFFF01 31 | 32 | #define WACOMCLASS_SERIAL 0x0001 33 | #define WACOMCLASS_USB 0x0002 34 | 35 | #define WACOMDEVICE_UNKNOWN 0x0000 36 | #define WACOMDEVICE_ARTPAD 0x0001 37 | #define WACOMDEVICE_ARTPADII 0x0002 38 | #define WACOMDEVICE_DIGITIZER 0x0003 39 | #define WACOMDEVICE_DIGITIZERII 0x0004 40 | #define WACOMDEVICE_PENPARTNER 0x0005 41 | #define WACOMDEVICE_GRAPHIRE 0x0006 42 | #define WACOMDEVICE_GRAPHIRE2 0x0007 43 | #define WACOMDEVICE_GRAPHIRE3 0x0008 44 | #define WACOMDEVICE_INTUOS 0x0009 45 | #define WACOMDEVICE_INTUOS2 0x000A 46 | #define WACOMDEVICE_CINTIQ 0x000B 47 | #define WACOMDEVICE_PTU 0x000C 48 | #define WACOMDEVICE_VOLITO 0x000D 49 | #define WACOMDEVICE_ACERC100 0x000E 50 | 51 | typedef struct _WACOMMODEL WACOMMODEL; 52 | struct _WACOMMODEL 53 | { 54 | unsigned int uClass; 55 | unsigned int uVendor; 56 | unsigned int uDevice; 57 | unsigned int uSubType; 58 | }; 59 | 60 | #define WACOMTOOLTYPE_NONE 0x00 61 | #define WACOMTOOLTYPE_PEN 0x01 62 | #define WACOMTOOLTYPE_PENCIL 0x02 63 | #define WACOMTOOLTYPE_BRUSH 0x03 64 | #define WACOMTOOLTYPE_ERASER 0x04 65 | #define WACOMTOOLTYPE_AIRBRUSH 0x05 66 | #define WACOMTOOLTYPE_MOUSE 0x06 67 | #define WACOMTOOLTYPE_LENS 0x07 68 | #define WACOMTOOLTYPE_MAX 0x08 69 | 70 | #define WACOMBUTTON_LEFT 0 71 | #define WACOMBUTTON_MIDDLE 1 72 | #define WACOMBUTTON_RIGHT 2 73 | #define WACOMBUTTON_EXTRA 3 74 | #define WACOMBUTTON_SIDE 4 75 | #define WACOMBUTTON_TOUCH 5 76 | #define WACOMBUTTON_STYLUS 6 77 | #define WACOMBUTTON_STYLUS2 7 78 | #define WACOMBUTTON_MAX 8 79 | 80 | #define WACOMFIELD_TOOLTYPE 0 81 | #define WACOMFIELD_SERIAL 1 82 | #define WACOMFIELD_PROXIMITY 2 83 | #define WACOMFIELD_BUTTONS 3 84 | #define WACOMFIELD_POSITION_X 4 85 | #define WACOMFIELD_POSITION_Y 5 86 | #define WACOMFIELD_ROTATION_Z 6 87 | #define WACOMFIELD_DISTANCE 7 88 | #define WACOMFIELD_PRESSURE 8 89 | #define WACOMFIELD_TILT_X 9 90 | #define WACOMFIELD_TILT_Y 10 91 | #define WACOMFIELD_ABSWHEEL 11 92 | #define WACOMFIELD_RELWHEEL 12 93 | #define WACOMFIELD_THROTTLE 13 94 | #define WACOMFIELD_MAX 14 95 | 96 | typedef struct 97 | { 98 | int nValue; 99 | int nMin; 100 | int nMax; 101 | int nReserved; 102 | } WACOMVALUE; 103 | 104 | typedef struct 105 | { 106 | unsigned int uValueCnt; /* This MUST be set to WACOMFIELD_MAX. */ 107 | unsigned int uValid; /* Bit mask of WACOMFIELD_xxx bits. */ 108 | WACOMVALUE values[WACOMFIELD_MAX]; 109 | } WACOMSTATE; 110 | 111 | #define WACOMSTATE_INIT { WACOMFIELD_MAX } 112 | 113 | typedef struct 114 | { 115 | const char* pszName; 116 | const char* pszDesc; 117 | unsigned int uDeviceClass; 118 | } WACOMCLASSREC; 119 | 120 | typedef struct 121 | { 122 | const char* pszName; 123 | const char* pszDesc; 124 | const char* pszVendorName; 125 | const char* pszVendorDesc; 126 | const char* pszClass; 127 | WACOMMODEL model; 128 | } WACOMDEVICEREC; 129 | 130 | typedef enum 131 | { 132 | WACOMLOGLEVEL_NONE, 133 | WACOMLOGLEVEL_CRITICAL, 134 | WACOMLOGLEVEL_ERROR, 135 | WACOMLOGLEVEL_WARN, 136 | WACOMLOGLEVEL_INFO, 137 | WACOMLOGLEVEL_DEBUG, 138 | WACOMLOGLEVEL_TRACE, 139 | WACOMLOGLEVEL_MAX 140 | } WACOMLOGLEVEL; 141 | 142 | typedef void (*WACOMLOGFUNC)(struct timeval tv, WACOMLOGLEVEL level, 143 | const char* pszLog); 144 | 145 | /***************************************************************************** 146 | ** Public structures 147 | *****************************************************************************/ 148 | 149 | typedef struct { int __unused; } *WACOMENGINE; 150 | typedef struct { int __unused; } *WACOMTABLET; 151 | 152 | /***************************************************************************** 153 | ** Public API 154 | *****************************************************************************/ 155 | 156 | WACOMENGINE WacomInitEngine(void); 157 | /* Initialize the tablet engine */ 158 | 159 | void WacomTermEngine(WACOMENGINE hEngine); 160 | /* Shutdown the tablet engine */ 161 | 162 | void WacomSetLogFunc(WACOMENGINE hEngine, WACOMLOGFUNC pfnLog); 163 | void WacomSetLogLevel(WACOMENGINE hEngine, WACOMLOGLEVEL level); 164 | void WacomLogV(WACOMENGINE hEngine, WACOMLOGLEVEL level, 165 | const char* pszFmt, va_list args); 166 | void WacomLog(WACOMENGINE hEngine, WACOMLOGLEVEL level, 167 | const char* pszFmt, ...); 168 | /* Logging functions. Default log function does nothing. */ 169 | 170 | int WacomGetSupportedClassList(WACOMCLASSREC** ppList, int* pnSize); 171 | /* Returns 0 on success. Pointer to class record list is returned to 172 | * ppList, and size of list to pnSize. Use WacomFreeList to release. */ 173 | 174 | int WacomGetSupportedDeviceList(unsigned int uDeviceClass, 175 | WACOMDEVICEREC** ppList, int* pnSize); 176 | /* Returns 0 on success. If device class is specified, only devices 177 | * of the request type are returned. A value of 0 will return all 178 | * devices for all classes. Pointer to device record list is returned to 179 | * ppList, and size of list to pnSize. Use WacomFreeList to release. */ 180 | 181 | void WacomFreeList(void* pvList); 182 | /* Releases list memory. */ 183 | 184 | int WacomCopyState(WACOMSTATE* pDest, WACOMSTATE* pSrc); 185 | /* Returns 0 on success. Copies tablet state structures. 186 | * Source and destination structures must be properly initialized, 187 | * particularly the uValueCnt field must be set WACOMFIELD_MAX. 188 | * Returns 0 on success. */ 189 | 190 | unsigned int WacomGetClassFromName(const char* pszName); 191 | /* Returns the device class for a given name. Returns 0, if unknown. */ 192 | 193 | unsigned int WacomGetDeviceFromName(const char* pszName, 194 | unsigned int uDeviceClass); 195 | /* Returns the device type for a given device name. If the 196 | * device class is specified, only that class will be searched. 197 | * Returns 0, if unknown. */ 198 | 199 | WACOMTABLET WacomOpenTablet(WACOMENGINE hEngine, 200 | const char* pszDevice, WACOMMODEL* pModel); 201 | /* Returns tablet handle on success, NULL otherwise. 202 | * pszDevice is pathname to device. Model may be NULL; if any model 203 | * parameters are 0, detection is automatic. */ 204 | 205 | void WacomCloseTablet(WACOMTABLET hTablet); 206 | /* Releases all resource associated with tablet and closes device. */ 207 | 208 | WACOMMODEL WacomGetModel(WACOMTABLET hTablet); 209 | /* Returns model (vendor, class, and device) of specified tablet. */ 210 | 211 | const char* WacomGetVendorName(WACOMTABLET hTablet); 212 | /* Returns vendor name as human-readable string. String is valid as 213 | * long as tablet handle is valid and does not need to be freed. */ 214 | 215 | const char* WacomGetClassName(WACOMTABLET hTablet); 216 | /* Returns class name as human-readable string. String is valid as 217 | * long as tablet handle is valid and does not need to be freed. */ 218 | 219 | const char* WacomGetDeviceName(WACOMTABLET hTablet); 220 | /* Returns device name as human-readable string. String is valid as 221 | * long as tablet handle is valid and does not need to be freed. */ 222 | 223 | const char* WacomGetSubTypeName(WACOMTABLET hTablet); 224 | /* Returns subtype name as human-readable string. This is typically 225 | * the model number (eg. ABC-1234). String is valid as long as tablet 226 | * handle is valid and does not need to be freed. */ 227 | 228 | const char* WacomGetModelName(WACOMTABLET hTablet); 229 | /* Returns model name as human-readable string. This is typically 230 | * the full model name (eg. FooCo FooModel 9x12). String is valid as 231 | * long as tablet handle is valid and does not need to be freed. */ 232 | 233 | int WacomGetROMVersion(WACOMTABLET hTablet, int* pnMajor, int* pnMinor, 234 | int* pnRelease); 235 | /* Returns 0 on success. ROM version of the tablet firmware is returned 236 | * in major, minor, and release values. If the caller needs to 237 | * distinguish between ROM versions to work around a bug, please consider 238 | * submitting a patch to this library. All tablets should appear 239 | * equivalent through this interface. This call is provided for 240 | * information purposes. */ 241 | 242 | int WacomGetCapabilities(WACOMTABLET hTablet); 243 | /* Returns bitmask of valid fields. Use (1 << WACOMFIELD_xxx) to 244 | * translate field identifiers to bit positions. This API will only 245 | * support 32 capabilities. */ 246 | 247 | int WacomGetState(WACOMTABLET hTablet, WACOMSTATE* pState); 248 | /* Returns 0 on success. Tablet state is copied to specified structure. 249 | * Data is only a snapshot of the device and may not accurately reflect 250 | * the position of any specific tool. This is particularly true of 251 | * multi-tool mode tablets. NOTE: pState must point to an initialized 252 | * structure; the uValueCnt field must be correctly set to 253 | * WACOMFIELD_MAX. */ 254 | 255 | int WacomGetFileDescriptor(WACOMTABLET hTablet); 256 | /* Returns the file descriptor of the tablet or -1 on error. */ 257 | 258 | int WacomReadRaw(WACOMTABLET hTablet, unsigned char* puchData, 259 | unsigned int uSize); 260 | /* Returns number of bytes read, typically a single packet. Call will 261 | * block. uSize should be the maximum size of the given data buffer. */ 262 | 263 | int WacomParseData(WACOMTABLET hTablet, const unsigned char* puchData, 264 | unsigned int uLength, WACOMSTATE* pState); 265 | /* Updates the tablet state from a given packet. If pState is specified, 266 | * the tablet state is copied to the given structure. This structure 267 | * must be correctly initialized; the uValueCnt member must be set to 268 | * WACOMFIELD_MAX. Returns 0 on success. */ 269 | 270 | /***************************************************************************** 271 | ** Private structures 272 | *****************************************************************************/ 273 | 274 | typedef struct _WACOMTABLET_PRIV WACOMTABLET_PRIV; 275 | 276 | struct _WACOMTABLET_PRIV 277 | { 278 | void (*Close)(WACOMTABLET_PRIV* pTablet); 279 | WACOMMODEL (*GetModel)(WACOMTABLET_PRIV* pTablet); 280 | const char* (*GetVendorName)(WACOMTABLET_PRIV* pTablet); 281 | const char* (*GetClassName)(WACOMTABLET_PRIV* pTablet); 282 | const char* (*GetDeviceName)(WACOMTABLET_PRIV* pTablet); 283 | const char* (*GetSubTypeName)(WACOMTABLET_PRIV* pTablet); 284 | const char* (*GetModelName)(WACOMTABLET_PRIV* pTablet); 285 | int (*GetROMVer)(WACOMTABLET_PRIV* pTablet, int* pnMajor, int* pnMinor, 286 | int* pnRelease); 287 | int (*GetCaps)(WACOMTABLET_PRIV* pTablet); 288 | int (*GetState)(WACOMTABLET_PRIV* pTablet, WACOMSTATE* pState); 289 | int (*GetFD)(WACOMTABLET_PRIV* pTablet); 290 | int (*ReadRaw)(WACOMTABLET_PRIV* pTablet, unsigned char* puchData, 291 | unsigned int uSize); 292 | int (*ParseData)(WACOMTABLET_PRIV* pTablet, const unsigned char* puchData, 293 | unsigned int uLength, WACOMSTATE* pState); 294 | }; 295 | 296 | #endif /* __LINUXWACOM_WACTABLET_H */ 297 | -------------------------------------------------------------------------------- /daemon/Daemon_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for TabletMagicDaemon 3 | // 4 | 5 | #include 6 | #include 7 | 8 | #include "Constants.h" 9 | 10 | 11 | #define FALLBACK_TO_SD 0 12 | #define LOG_STREAM_TO_FILE 0 13 | 14 | #define kSerialError -1 15 | 16 | -------------------------------------------------------------------------------- /daemon/SerialDaemon.h: -------------------------------------------------------------------------------- 1 | /** 2 | * SerialDaemon.h 3 | * 4 | * TabletMagicDaemon 5 | * Thinkyhead Software 6 | * 7 | * This program is a component of TabletMagic. See the 8 | * accompanying documentation for more details about the 9 | * TabletMagic project. 10 | * 11 | * LICENSE 12 | * 13 | * This program is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU Library General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 2 of the License, or (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Library General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU Library General Public 24 | * License along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 | */ 27 | 28 | #include "TabletSettings.h" 29 | #include "TMSerialPort.h" 30 | 31 | // 32 | // Wacom.h is a very sparse header provided by Wacom. 33 | // It is included here for completeness. 34 | // 35 | #include "Wacom.h" 36 | 37 | #include 38 | #include 39 | 40 | #pragma mark - 41 | 42 | #define kNumRetries 3 43 | 44 | 45 | //! Command-line options 46 | typedef struct init_arguments { 47 | bool quiet; //!< suppress diagnostic messages 48 | bool command; //!< run in command mode 49 | #if __MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 50 | bool dodaemon; //!< run as a daemon 51 | #endif 52 | bool forcepc; //!< always assume ISD-V4 at 19200 53 | bool baud38400; //!< initially try 38400 54 | bool startoff; //!< start up in disabled mode 55 | bool quit; //!< quit after testing the connection 56 | bool logging; //!< redirect output to a log file 57 | char *port; //!< the serial port to connect to (null = Automatic) 58 | char *init; //!< initial setup string to send to the tablet 59 | char *digi; //!< digitizer string, if any 60 | int rate; //!< initial baud rate (default 9600) 61 | 62 | bool mouse; //!< operate in mouse mode 63 | float scaling; //!< initial mouse scaling (default 1.0) 64 | 65 | int priority; //!< process priority (-20 to 20) 66 | 67 | int tab_left; //!< initial tablet left boundary 68 | int tab_top; //!< initial tablet top boundary 69 | int tab_right; //!< initial tablet right boundary 70 | int tab_bottom; //!< initial tablet bottom boundary 71 | 72 | int scr_left; //!< initial screen left boundary 73 | int scr_top; //!< initial screen top boundary 74 | int scr_right; //!< initial screen right boundary 75 | int scr_bottom; //!< initial screen bottom boundary 76 | } init_arguments; 77 | 78 | typedef struct { 79 | CGPoint scrPos, oldPos; // Screen position (tracked by the tablet object) 80 | struct { SInt32 x, y; } point; // Tablet-level X / Y coordinates 81 | struct { SInt32 x, y; } old; // Old coordinates used to calculate mouse mode 82 | struct { SInt32 x, y; } motion; // Tablet-level X / Y motion 83 | struct { SInt16 x, y; } tilt; // Current tilt, scaled for NX Event usage 84 | UInt16 raw_pressure; //!< Previous raw pressure (for SD II-S ASCII) 85 | UInt16 pressure; //!< Current pressure, scaled for NX Event usage 86 | bool button_click; //!< a button is clicked 87 | UInt16 button_mask; //!< Bits set here for each button 88 | bool button[kButtonMax]; //!< Booleans for each button 89 | bool off_tablet; //!< nothing is near or clicked 90 | bool pen_near; //!< pen or eraser is near or clicked 91 | bool eraser_flag; //!< eraser is near or clicked 92 | UInt16 menu_button; //!< Last menu button pressed (clear after handling) 93 | 94 | // Intuos 95 | UInt16 tool; //!< Intuos supports several tools 96 | int toolid; //!< Tool ID passed on to system for apps to recognize 97 | long serialno; //!< Serial number of the selected tool 98 | SInt16 rotation; //!< Rotation from the 4D mouse 99 | SInt16 wheel; //!< The 2D Mouse has a wheel 100 | SInt16 throttle; //!< The mouse has a throttle (-1023 to 1023) 101 | 102 | NXTabletProximityData proximity; //!< Proximity data description 103 | 104 | } StylusState; 105 | 106 | 107 | #pragma mark - 108 | 109 | class WacomTablet { 110 | 111 | private: 112 | bool tablet_on; //!< If true, events are generated from tablet data 113 | bool doing_modal; //!< True when awaiting a modal command reply 114 | int bank_last_requested; //!< For ArtZ tablets, the settings bank last queried 115 | 116 | bool send_stream; //!< If true then pass tablet events to the pref pane 117 | char stream_packet[500]; //!< The most recent packet processed 118 | char *stream_event; //!< The most recent event 119 | char stream_size; //!< The most recent packet size 120 | 121 | CFRunLoopTimerRef streamTimer; //!< Seconds counter to support rate counting 122 | CFMessagePortRef local_message_port; //!< To receive messages from the pref pane 123 | Boolean portShouldFree; 124 | 125 | #if ASYNCHRONOUS_MESSAGING 126 | CFMessagePortRef remote_message_port; //!< To send messages to the pref pane 127 | #else 128 | bool messageQueueEnabled; //!< Whether this queue is enabled 129 | CFMutableArrayRef outgoing_message_queue; //!< Messages bound for the pref pane 130 | #endif 131 | 132 | char model_number[64]; //!< The model number, as received from ~# 133 | char rom_version[64]; //!< The ROM version, as received from ~# 134 | float base_version; //!< The base version of the ROM, as received from ~# 135 | SeriesIndex series_index; //!< The type of tablet, based on 136 | bool can_parse_ud_setup; //!< Flag for UD parsing ability (not SD or TPC) 137 | 138 | /*! Internal tablet settings 139 | 140 | [0] is the active setting 141 | [1] and [2] are the ArtZ memory bank settings 142 | */ 143 | TabletSettings settings[3]; 144 | 145 | StylusState stylus; //!< The state of the (single) stylus 146 | StylusState oldStylus; //!< A mirrored state used to track changes 147 | bool buttonState[kSystemClickTypes]; //!< The state of all the system-level buttons 148 | bool oldButtonState[kSystemClickTypes]; //!< The previous state of all system-level buttons 149 | 150 | TMSerialPort serialPort; //!< The serial port instance associated with this tablet 151 | 152 | char phrase[100]; //!< A single "phrase" of the tablet stream, with room to spare 153 | int phrase_count; //!< length of the phrase so far 154 | int comma_count; //!< comma counting for model replies of certain tablets 155 | char buffer[1024]; //!< Buffer for the raw stream, with room to spare 156 | char modalbuffer[1024]; //!< Buffer for the raw stream when awaiting modal replies 157 | char out_message[200]; //!< A buffer for composing messages sent to the pref pane 158 | 159 | int commandSent; //!< Flag if we are waiting for a command result 160 | 161 | bool mouse_mode; //!< If set, the tablet behaves like a mouse 162 | float mouse_scaling; //!< Mouse motion relative to tablet motion 163 | 164 | bool test_mode; //!< If set, quit after initial connection 165 | bool quiet_mode; //!< If set, don't print any messages 166 | 167 | bool in_packet; //!< Set when a packet start bit is detected 168 | 169 | CGRect tabletMapping; //!< The active area of the tablet 170 | CGRect screenMapping; //!< The corresponding active area of the screen 171 | 172 | mach_port_t io_master_port; //!< The master port for HID events 173 | io_connect_t gEventDriver; //!< The connection by which HID events are sent 174 | 175 | public: 176 | WacomTablet(init_arguments); 177 | ~WacomTablet(); 178 | 179 | void InitializeForPort(char *port_name); 180 | void InitStylus(); 181 | void ResetStylus(); 182 | bool FindTabletOnPort(char *port_name=NULL); 183 | bool InitializeTablet(int try_tablet_model=kModelUnknown); 184 | bool SendCommandToTablet(const char *command); 185 | int SendRequestToTablet(const char *command); 186 | 187 | void SendUDSetupString(char *setup, int bank=0, bool insist=true); 188 | void RequestUDSettings(int bank=0); 189 | char* GetUDSettings(int bank=0); 190 | bool GetUDSettingsOrFail(int bank=0); 191 | 192 | bool SendScaleToTablet(int h, int v); 193 | 194 | bool IsActive() { return serialPort.IsActive(); } 195 | inline bool AwaitingModalReply() { return doing_modal; } 196 | 197 | void SetTestMode(bool b=true) { test_mode = b; } 198 | void SetQuietMode(bool b=true) { quiet_mode = b; } 199 | void SetMouseMode(bool b=true) { mouse_mode = b; stylus.oldPos = stylus.scrPos; } 200 | void SetMouseScaling(float s=1.0) { mouse_scaling = s; } 201 | void SetScreenMapping(SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2); 202 | void InitTabletBounds(SInt32 x1, SInt32 y1, SInt32 x2, SInt32 y2); 203 | void UpdateTabletScale(SInt32 h, SInt32 v, bool tellprefs=false); 204 | 205 | void RequestTabletID() { SendCommandToTablet(WAC_TabletID); } 206 | void RequestMaxCoordinates() { SendCommandToTablet(WAC_TabletSize); } 207 | 208 | char* RequestTabletIDModal() { SendRequestToTablet(WAC_TabletID); return modalbuffer; } 209 | char* RequestMaxCoordinatesModal() { SendRequestToTablet(WAC_TabletSize); return modalbuffer; } 210 | 211 | char* RequestCalCompIDModal() { SendRequestToTablet(CAL_TabletID); return modalbuffer; } 212 | char* RequestCalCompMaxCoordinatesModal(){ SendRequestToTablet(CAL_TabletSize); return modalbuffer; } 213 | 214 | void RunEventLoop(); 215 | static void TabletTimerCallback( CFRunLoopTimerRef timer, void *info ); 216 | static void EventTimerCallback( CFRunLoopTimerRef timer, void *info ); 217 | 218 | void SetStreamLogging(bool do_stream); 219 | static void StreamTimerCallback( CFRunLoopTimerRef timer, void *info ); 220 | 221 | void ProcessSerialStream(); 222 | void ProcessPacket(char *pkt, int size); 223 | void ProcessCommandReply(char *response); 224 | void ProcessTabletPCCommandReply(char *response); 225 | void ProcessCalCompCommandReply(char *response); 226 | 227 | void ProcessWacomIIS_ASCII(char *pkt, int size); 228 | void ProcessWacomIIS_Binary(char *pkt, int size); 229 | void ProcessWacomIV_Base(char *pkt, int size); 230 | void ProcessWacomIV_13(char *pkt, int size); 231 | void ProcessWacomIV_14(char *pkt, int size); 232 | void ProcessWacomV(char *pkt, int size); 233 | void ProcessGraphire(char *pkt, int size); 234 | void ProcessTabletPC(char *pkt, int size); 235 | void ProcessFinepoint(char *pkt, int size); 236 | void ProcessFujitsuPSeries(char *pkt); 237 | 238 | void PostChangeEvents(); 239 | void PostNXEvent(int eventType, SInt16 eventSubType, UInt8 otherButton=0); 240 | void PostCGEvent(CGEventType eventType, SInt16 eventSubType, CGMouseButton otherButton=kCGMouseButtonLeft, UInt16 clickCount=1); 241 | 242 | void ApplySettings(int i); 243 | 244 | inline int Flush() { return serialPort.Flush(); } 245 | 246 | kern_return_t OpenHIDService(); 247 | kern_return_t CloseHIDService(); 248 | 249 | void RegisterForNotifications(); 250 | void DisableNotifications(); 251 | static void PowerCallBack(void *x, io_service_t y, natural_t messageType, void *messageArgument); 252 | static void ResolutionChangeCallback( CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo ); 253 | static void DisplayCallback(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *userInfo); 254 | void ScreenChanged(); 255 | 256 | void CreateLocalMessagePort(); 257 | 258 | #if ASYNCHRONOUS_MESSAGING 259 | CFMessagePortRef GetRemoteMessagePort(); 260 | static void invalidation_callback(CFMessagePortRef ms, void *info); 261 | void HandleInvalidation(CFMessagePortRef ms); 262 | #else 263 | void AddMessageToQueue(CFDataRef message); 264 | void FlushMessageQueue(); 265 | char* PopMessageQueue(); 266 | inline void EnableMessageQueue() { FlushMessageQueue(); messageQueueEnabled = true; } 267 | inline void DisableMessageQueue() { messageQueueEnabled = false; FlushMessageQueue(); } 268 | #endif 269 | 270 | static CFDataRef message_callback(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info); 271 | CFDataRef HandleMessage(CFMessagePortRef local, SInt32 msgid, CFDataRef data); 272 | void SendMessage(const char *message); 273 | void SendMessage(CFDataRef message); 274 | 275 | void SendMessageInfo(int bank=0); 276 | void SendMessageScale(); 277 | void SendMessageModel(); 278 | void SendMessageProtocol(); 279 | 280 | char* GetMessageInfo(int bank=0); 281 | char* GetMessageScale(); 282 | char* GetMessageModel(); 283 | char* GetMessageProtocol(); 284 | char* GetMessageGeometry(); 285 | char* GetMessageStream(); 286 | char* GetMessageSerialPort(); 287 | 288 | // Commands - As sent by the PreferencePane 289 | void SetProcessing(bool ena) { tablet_on = ena; } 290 | }; 291 | 292 | -------------------------------------------------------------------------------- /daemon/TMSerialPort.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * TMSerialPort.cpp 3 | * 4 | * TabletMagicDaemon 5 | * Thinkyhead Software 6 | * 7 | * This program is a component of TabletMagic. See the 8 | * accompanying documentation for more details about the 9 | * TabletMagic project. 10 | * 11 | * LICENSE 12 | * 13 | * This program is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU Library General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 2 of the License, or (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Library General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU Library General Public 24 | * License along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 | */ 27 | 28 | #include "TMSerialPort.h" 29 | #include "TabletSettings.h" 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #if LOG_STREAM_TO_FILE 50 | extern FILE* logfile; 51 | #endif 52 | 53 | TMSerialPort::TMSerialPort() { 54 | output = NULL; 55 | fd = kSerialError; // No serial port yet 56 | (void)SetDefaultParameters(); 57 | } 58 | 59 | TMSerialPort::~TMSerialPort() { 60 | Close(); 61 | } 62 | 63 | bool TMSerialPort::SetDefaultParameters() { 64 | return SetParameters(B9600, CS8, 0, 1, false, false); 65 | } 66 | 67 | bool TMSerialPort::SetParameters(TabletSettings *sett) { 68 | speed_t rate[] = { B2400, B4800, B9600, B19200, B38400 }; 69 | int parity[] = { 0, 0, 1, 2 }; 70 | 71 | return SetParameters(rate[sett->baud_rate], (sett->data_bits ? CS8 : CS7), parity[sett->parity], (sett->stop_bits ? 2 : 1), sett->cts, sett->dsr); 72 | } 73 | 74 | bool TMSerialPort::SetParameters(speed_t speed, tcflag_t databits, int parity, int stopbits, bool cts, bool dsr) { 75 | openSpeed = speed; 76 | openDataBits = databits; 77 | openParity = parity; 78 | openStopBits = stopbits; 79 | openCTS = cts; 80 | openDSR = dsr; 81 | 82 | return ApplySettings(); 83 | } 84 | 85 | int TMSerialPort::ReInit(TabletSettings *sett) { 86 | Close(); 87 | (void)SetParameters(sett); 88 | return Open(); 89 | } 90 | 91 | int TMSerialPort::Open(char *filepath) { 92 | int handshake; 93 | struct termios attribs; 94 | 95 | if (filepath != NULL) 96 | strcpy(deviceFilePath, filepath); 97 | 98 | strcpy(shortName, deviceFilePath + (strstr(deviceFilePath, "/dev/cu.") ? 8 : (strstr(deviceFilePath, "/dev/") ? 5 : 0))); 99 | 100 | // Open the serial port read/write, with no controlling terminal, 101 | // and don't wait for a connection. 102 | // The O_NONBLOCK flag also causes subsequent I/O on the device to 103 | // be non-blocking. 104 | // See open(2) ("man 2 open") for details. 105 | 106 | fd = open(deviceFilePath, O_RDWR | O_NOCTTY | O_NONBLOCK); 107 | if (fd == kSerialError) { 108 | if (output != NULL) 109 | fprintf(output, "Error opening serial port %s - %s(%d).\n", deviceFilePath, strerror(errno), errno); 110 | goto error; 111 | } 112 | 113 | // Note that open() follows POSIX semantics: multiple open() calls to 114 | // the same file will succeed unless the TIOCEXCL ioctl is issued. 115 | // This will prevent additional opens except by root-owned processes. 116 | // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details. 117 | 118 | if (ioctl(fd, TIOCEXCL) == kSerialError) { 119 | if (output != NULL) 120 | fprintf(output, "Error setting TIOCEXCL on %s - %s(%d).\n", deviceFilePath, strerror(errno), errno); 121 | goto error; 122 | } 123 | 124 | // Now that the device is open, clear the O_NONBLOCK flag so 125 | // subsequent I/O will block. 126 | // See fcntl(2) ("man 2 fcntl") for details. 127 | 128 | if (fcntl(fd, F_SETFL, 0) == kSerialError) { 129 | if (output != NULL) 130 | fprintf(output, "Error clearing O_NONBLOCK %s - %s(%d).\n", deviceFilePath, strerror(errno), errno); 131 | goto error; 132 | } 133 | 134 | // Get the current options and save them so we can restore the 135 | // default settings later. 136 | if (tcgetattr(fd, &originalAttribs) == kSerialError) { 137 | if (output != NULL) 138 | fprintf(output, "Error getting tty attributes %s - %s(%d).\n", deviceFilePath, strerror(errno), errno); 139 | goto error; 140 | } 141 | 142 | // The serial port attributes such as timeouts and baud rate are set by 143 | // modifying the termios structure and then calling tcsetattr to 144 | // cause the changes to take effect. Note that the 145 | // changes will not take effect without the tcsetattr() call. 146 | // See tcsetattr(4) ("man 4 tcsetattr") for details. 147 | 148 | attribs = originalAttribs; 149 | 150 | // Print the current input and output baud rates. 151 | // See tcsetattr(4) ("man 4 tcsetattr") for details. 152 | 153 | // if (output != NULL) { 154 | // fprintf(output, "Current input baud rate is %d\n", (int) cfgetispeed(&attribs)); 155 | // fprintf(output, "Current output baud rate is %d\n", (int) cfgetospeed(&attribs)); 156 | // } 157 | 158 | // Set raw input (non-canonical) mode, with reads blocking until either 159 | // a single character has been received or a one second timeout expires. 160 | // See tcsetattr(4) ("man 4 tcsetattr") and termios(4) ("man 4 termios") 161 | // for details. 162 | 163 | cfmakeraw(&attribs); 164 | attribs.c_cc[VMIN] = 1; // 1 byte minimum 165 | attribs.c_cc[VTIME] = 10; // 1 second 166 | 167 | // The Baud Rate 168 | cfsetspeed(&attribs, openSpeed); // Set the baud rate 169 | 170 | // Data Bits - 7 or 8 171 | attribs.c_cflag &= ~CSIZE; // Clear the data size bits 172 | attribs.c_cflag |= openDataBits; // Set the data size 173 | 174 | // Parity N-O-E 175 | switch(openParity) { 176 | case 0: 177 | attribs.c_cflag &= ~PARENB; 178 | break; 179 | case 1: 180 | attribs.c_cflag |= (PARENB|PARODD); 181 | break; 182 | case 2: 183 | attribs.c_cflag |= PARENB; 184 | attribs.c_cflag &= ~PARODD; 185 | break; 186 | } 187 | 188 | // Stop Bits 1 or 2 189 | if (openStopBits == 2) 190 | attribs.c_cflag |= CSTOPB; 191 | else 192 | attribs.c_cflag &= ~CSTOPB; 193 | 194 | // Cause the new attribs to take effect immediately. 195 | if (tcsetattr(fd, TCSANOW, &attribs) == kSerialError) { 196 | if (output != NULL) 197 | fprintf(output, "Error setting tty attributes %s - %s(%d).\n", deviceFilePath, strerror(errno), errno); 198 | goto error; 199 | } 200 | 201 | // Print the new input and output baud rates. 202 | // if (output != NULL) { 203 | // fprintf(output, "Input baud rate changed to %d\n", (int) cfgetispeed(&attribs)); 204 | // fprintf(output, "Output baud rate changed to %d\n", (int) cfgetospeed(&attribs)); 205 | // } 206 | 207 | // Assert Data Terminal Ready (DTR) 208 | // To set the port handshake lines, use the following ioctls. 209 | // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details. 210 | if (ioctl(fd, TIOCSDTR) == kSerialError && output != NULL) 211 | fprintf(output, "Error asserting DTR %s - %s(%d).\n", deviceFilePath, strerror(errno), errno); 212 | 213 | // Clear Data Terminal Ready (DTR) 214 | if (ioctl(fd, TIOCCDTR) == kSerialError && output != NULL) 215 | fprintf(output, "Error clearing DTR %s - %s(%d).\n", deviceFilePath, strerror(errno), errno); 216 | 217 | // Set the serial port lines depending on the bits set in handshake. 218 | handshake = TIOCM_DTR | TIOCM_RTS; 219 | 220 | if (openCTS) 221 | handshake |= TIOCM_CTS; 222 | 223 | if (openDSR) 224 | handshake |= TIOCM_DSR; 225 | 226 | if (ioctl(fd, TIOCMSET, &handshake) == kSerialError && output != NULL) 227 | fprintf(output, "Error setting handshake lines %s - %s(%d).\n", deviceFilePath, strerror(errno), errno); 228 | 229 | // Store the state of the serial port lines in handshake. 230 | // To read the state of the port's lines, use the following ioctl. 231 | // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details. 232 | if (ioctl(fd, TIOCMGET, &handshake) == kSerialError && output != NULL) 233 | fprintf(output, "Error getting handshake lines %s - %s(%d).\n", deviceFilePath, strerror(errno), errno); 234 | 235 | // if (output != NULL) 236 | // fprintf(output, "Handshake lines currently set to %d\n", handshake); 237 | 238 | // Success: 239 | return fd; 240 | 241 | // Failure: 242 | error: 243 | if (fd != kSerialError) { 244 | close(fd); 245 | fd = kSerialError; 246 | } 247 | 248 | return fd; 249 | } 250 | 251 | // 252 | // ApplySettings 253 | // 254 | bool TMSerialPort::ApplySettings() { 255 | bool result = true; 256 | 257 | if (IsOpen()) { 258 | result = false; 259 | struct termios attribs; 260 | 261 | if (tcgetattr(fd, &attribs) != kSerialError) { 262 | cfsetspeed(&attribs, openSpeed); 263 | 264 | // Data Bits - 7 or 8 265 | attribs.c_cflag &= ~CSIZE; // Clear the data size bits 266 | attribs.c_cflag |= openDataBits; // Set the data size 267 | 268 | // Parity N-O-E 269 | switch(openParity) { 270 | case 0: 271 | attribs.c_cflag &= ~PARENB; 272 | break; 273 | case 1: 274 | attribs.c_cflag |= (PARENB|PARODD); 275 | break; 276 | case 2: 277 | attribs.c_cflag |= PARENB; 278 | attribs.c_cflag &= ~PARODD; 279 | break; 280 | } 281 | 282 | // Stop Bits 1 or 2 283 | if (openStopBits == 2) 284 | attribs.c_cflag |= CSTOPB; 285 | else 286 | attribs.c_cflag &= ~CSTOPB; 287 | 288 | if (tcsetattr(fd, TCSANOW|TCSAFLUSH, &attribs) != kSerialError) { 289 | result = true; 290 | } 291 | else { 292 | if (output != NULL) 293 | fprintf(output, "Error setting tty attributes %s - %s(%d).\n", deviceFilePath, strerror(errno), errno); 294 | } 295 | } 296 | else { 297 | if (output != NULL) 298 | fprintf(output, "Error getting tty attributes %s - %s(%d).\n", deviceFilePath, strerror(errno), errno); 299 | } 300 | } 301 | return result; 302 | } 303 | 304 | // 305 | // CloseSerialPort() 306 | // 307 | // Close the serial port. 308 | // We close the serial port when switching ports or quitting. 309 | // 310 | void TMSerialPort::Close() { 311 | if (fd != kSerialError) { 312 | // Block until all written output has been sent from the device. 313 | // Note that this call is simply passed on to the serial device driver. 314 | // See tcsendbreak(3) ("man 3 tcsendbreak") for details. 315 | if (tcdrain(fd) == kSerialError && output != NULL) 316 | fprintf(output, "Error waiting for drain - %s(%d).\n", strerror(errno), errno); 317 | 318 | // It is good practice to reset a serial port back to the state in 319 | // which you found it. This is why we saved the original termios struct 320 | // The constant TCSANOW (defined in termios.h) indicates that 321 | // the change should take effect immediately. 322 | if (tcsetattr(fd, TCSANOW, &originalAttribs) == kSerialError && output != NULL) 323 | fprintf(output, "Error resetting tty attributes - %s(%d).\n", strerror(errno), errno); 324 | 325 | close(fd); 326 | fd = kSerialError; 327 | } 328 | } 329 | 330 | // 331 | // Select(timeout) 332 | // 333 | // Timeout must be between 1 and 999999. 334 | // (Default: 4000us, 1/250th of a second) 335 | // 336 | // Returns n > 0 on success 337 | // 338 | int TMSerialPort::Select(__darwin_suseconds_t usec) { 339 | if (!IsOpen()) return -1; 340 | 341 | fd_set inputList; // A file descriptor set 342 | struct timeval timeout; // A one second timeout 343 | 344 | FD_ZERO(&inputList); 345 | FD_SET(fd, &inputList); 346 | timeout.tv_sec = 0; 347 | timeout.tv_usec = usec; 348 | 349 | // look for ready ports up to and including ours 350 | int n = select(fd + 1, &inputList, NULL, NULL, &timeout); 351 | 352 | if (n < 0) { 353 | // n < 0 when select fails 354 | if (output != NULL) 355 | fprintf(output, "[ERR ] TMSerialPort::Select() failed!\n"); 356 | } 357 | else if (n == 0) { 358 | // n == 0 if there are no ready ports 359 | } 360 | else if (!FD_ISSET(fd, &inputList)) { 361 | // FD_ISSET looks for our port in the list 362 | n = 0; 363 | } 364 | 365 | return n; 366 | } 367 | 368 | 369 | // 370 | // Read(buffer, maxlen) 371 | // 372 | int TMSerialPort::Read(char *buffer, int maxlen) { 373 | return (int)read(fd, buffer, maxlen); 374 | } 375 | 376 | 377 | // 378 | // Flush() 379 | // 380 | int TMSerialPort::Flush() { 381 | if (!IsOpen()) return -1; 382 | 383 | char ch[16]; 384 | fd_set fdsRead; 385 | struct timeval timeout; 386 | 387 | if (tcflush(fd, TCIFLUSH) == 0) 388 | return 0; 389 | 390 | timeout.tv_sec = 0; 391 | timeout.tv_usec = 0; 392 | 393 | while (1) { 394 | FD_ZERO(&fdsRead); 395 | FD_SET(fd, &fdsRead); 396 | if (select(FD_SETSIZE, &fdsRead, NULL, NULL, &timeout) <= 0) 397 | break; 398 | read(fd, &ch, sizeof(ch)); 399 | } 400 | 401 | return 0; 402 | } 403 | 404 | 405 | // 406 | // ReadLine(buffer, maxlen [,timeout]) 407 | // 408 | int TMSerialPort::ReadLine(char *buffer, int maxlen, __darwin_suseconds_t usec) { 409 | int numBytes = 0; 410 | char *bufPtr = buffer; 411 | bool gotLine = false, in_packet = false; 412 | 413 | // Loop while bytes await 414 | while (!gotLine && Select(usec) > 0) { 415 | // Loop through bytes received 416 | while (!gotLine && BytesOnPort()) { 417 | char temp[1]; 418 | numBytes = Read(temp, 1); 419 | 420 | if (numBytes > 0) { 421 | char c = temp[0]; 422 | 423 | if ((c & 0x80) != 0) { 424 | in_packet = true; 425 | #if LOG_STREAM_TO_FILE 426 | fprintf(logfile, "\n"); 427 | #endif 428 | } 429 | else if (c == '~') { 430 | in_packet = false; 431 | bufPtr = buffer; 432 | #if LOG_STREAM_TO_FILE 433 | fprintf(logfile, "\n"); 434 | #endif 435 | } 436 | 437 | #if LOG_STREAM_TO_FILE 438 | short b = ((short)c) & 0x00FF; 439 | fprintf(logfile, "-%02X", b); 440 | #endif 441 | 442 | if (!in_packet) { 443 | *bufPtr = c; 444 | if (c == '\n' || c == '\r') 445 | gotLine = true; 446 | else 447 | bufPtr++; 448 | } 449 | } 450 | else { 451 | gotLine = true; 452 | if (output != NULL) { 453 | if (numBytes == 0) 454 | fprintf(output, "[ERR ] No line waiting on the serial port\n"); 455 | else if (numBytes == kSerialError) 456 | fprintf(output, "[ERR ] (%d) %s\n", errno, strerror(errno)); 457 | } 458 | } 459 | 460 | } 461 | 462 | } 463 | 464 | *bufPtr = '\0'; 465 | 466 | #if LOG_STREAM_TO_FILE 467 | fprintf(logfile, "\n(%s)\n", buffer); 468 | #endif 469 | 470 | return (int)strlen(buffer); 471 | } 472 | 473 | int TMSerialPort::Write(char *buffer, int length) { 474 | return (int)write(fd, buffer, length); 475 | } 476 | 477 | int TMSerialPort::WriteString(char *string) { 478 | return (int)Write(string, (int)strlen(string)); 479 | } 480 | 481 | // 482 | // BytesOnPort 483 | // How many bytes are waiting on the serial port? 484 | // 485 | int TMSerialPort::BytesOnPort() { 486 | int bytes; 487 | ioctl(fd, FIONREAD, &bytes); 488 | return bytes; 489 | } 490 | 491 | #pragma mark - 492 | 493 | // 494 | // BeginPortScan(RS232Only?) 495 | // 496 | // Prepare a list of ports (i.e., that could have a tablet attached) 497 | // The result is stored in the tablet object's serialPortIterator data member 498 | // for use by FindTabletOnPort. 499 | // 500 | // Once again, thanks be to Apple for the samples. 501 | // 502 | kern_return_t TMSerialPort::BeginPortScan(bool RS232Only) { 503 | EndPortScan(); 504 | 505 | kern_return_t kernResult; 506 | mach_port_t masterPort; 507 | CFMutableDictionaryRef classesToMatch; 508 | 509 | // 510 | // Get the masterPort, whatever that is 511 | // 512 | kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort); 513 | if (KERN_SUCCESS != kernResult) { 514 | if (output != NULL) 515 | fprintf(output, "IOMasterPort returned %d\n", kernResult); 516 | goto exit; 517 | } 518 | 519 | // 520 | // Serial devices are instances of class IOSerialBSDClient. 521 | // Here I search for ports with RS232Type because with my 522 | // Keyspan USB-Serial adapter the first port shows up 523 | // 524 | classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); 525 | if (classesToMatch == NULL) { 526 | if (output != NULL) 527 | fprintf(output, "No BSD Serial Service?\n"); 528 | } 529 | else 530 | CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), RS232Only ? CFSTR(kIOSerialBSDRS232Type) : CFSTR(kIOSerialBSDAllTypes)); 531 | 532 | // 533 | // Find the next matching service 534 | // 535 | kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch, &serialPortIterator); 536 | if (KERN_SUCCESS != kernResult) { 537 | if (output != NULL) 538 | fprintf(output, "IOServiceGetMatchingServices returned %d\n", kernResult); 539 | goto exit; 540 | } 541 | 542 | exit: 543 | return kernResult; 544 | } 545 | 546 | void TMSerialPort::EndPortScan() { 547 | if (serialPortIterator != 0) { 548 | IOObjectRelease(serialPortIterator); 549 | serialPortIterator = 0; 550 | } 551 | } 552 | 553 | bool TMSerialPort::HasValidIterator() { 554 | return (serialPortIterator != 0) && IOIteratorIsValid(serialPortIterator); 555 | } 556 | 557 | // 558 | // GetNextPortPath 559 | // Get the path in /dev that represents the next eligible port. 560 | // 561 | // Muchas gracias to Apple for this code. 562 | // 563 | kern_return_t TMSerialPort::GetNextPortPath() { 564 | io_object_t portService; 565 | kern_return_t kernResult = KERN_FAILURE; 566 | 567 | clearstr(deviceFilePath); 568 | 569 | // Keep iterating until successful 570 | while ((portService = IOIteratorNext(serialPortIterator))) { 571 | CFTypeRef deviceFilePathAsCFString; 572 | 573 | // Get the callout device's path (/dev/cu.xxxxx). 574 | deviceFilePathAsCFString = IORegistryEntryCreateCFProperty( 575 | portService, 576 | CFSTR(kIOCalloutDeviceKey), 577 | kCFAllocatorDefault, 578 | 0); 579 | 580 | if (deviceFilePathAsCFString) { 581 | Boolean result; 582 | 583 | // Convert the path from CFString to C string 584 | result = CFStringGetCString((CFStringRef)deviceFilePathAsCFString, 585 | deviceFilePath, 586 | sizeof(deviceFilePath), 587 | kCFStringEncodingASCII); 588 | 589 | CFRelease(deviceFilePathAsCFString); 590 | 591 | if (result) { 592 | kernResult = KERN_SUCCESS; 593 | break; 594 | } 595 | } 596 | 597 | // Release the io_service_t now that we are done with it. 598 | (void) IOObjectRelease(portService); 599 | } 600 | 601 | return kernResult; 602 | } 603 | 604 | // 605 | // OpenNextMatchingPort 606 | // 607 | // This looks for the next selected port matching a given name 608 | // and tries to open it. 609 | // 610 | // Result: 611 | // true successfully opened a matching port 612 | // false ran out of openable ports 613 | // 614 | bool TMSerialPort::OpenNextMatchingPort(char *portname) { 615 | bool success = false; 616 | 617 | // Loop until success, the iterator dies, or we run out of paths 618 | while (!success && HasValidIterator() && GetNextPortPath() != KERN_FAILURE) { 619 | // Try the port if it matches the argument 620 | if ( portname == NULL || portname[0] == '\0' || NULL != strstr(deviceFilePath, portname) ) { 621 | // Try to open the serial port 622 | if (Open() != kSerialError) 623 | success = true; 624 | 625 | // Report the result 626 | if (output != NULL) 627 | fprintf(output, "\n[PORT] %s: %s\n", shortName, success ? "OPENED" : "OPEN ERROR"); 628 | } 629 | } 630 | 631 | return success; 632 | } 633 | 634 | -------------------------------------------------------------------------------- /daemon/TMSerialPort.h: -------------------------------------------------------------------------------- 1 | /** 2 | * TMSerialPort.h 3 | * 4 | * TabletMagicDaemon 5 | * Thinkyhead Software 6 | * 7 | * This program is a component of TabletMagic. See the 8 | * accompanying documentation for more details about the 9 | * TabletMagic project. 10 | * 11 | * LICENSE 12 | * 13 | * This program is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU Library General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 2 of the License, or (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Library General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU Library General Public 24 | * License along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 | */ 27 | 28 | #ifndef __TMSERIALPORT_H__ 29 | #define __TMSERIALPORT_H__ 30 | 31 | class TabletSettings; 32 | 33 | #include 34 | #include 35 | 36 | //=================================================================== 37 | // 38 | // TMSerialPort 39 | // 40 | // This class models a serial port 41 | // 42 | //=================================================================== 43 | 44 | class TMSerialPort { 45 | 46 | private: 47 | int fd; 48 | char deviceFilePath[MAXPATHLEN]; 49 | char shortName[MAXPATHLEN]; 50 | struct termios originalAttribs; 51 | io_iterator_t serialPortIterator; 52 | 53 | speed_t openSpeed; 54 | tcflag_t openDataBits; 55 | int openParity; 56 | int openStopBits; 57 | bool openCTS; 58 | bool openDSR; 59 | 60 | FILE *output; 61 | 62 | public: 63 | TMSerialPort(); 64 | ~TMSerialPort(); 65 | 66 | inline int FileDevice() { return fd; } 67 | inline char* DeviceFilePath() { return deviceFilePath; } 68 | inline bool IsOpen() { return fd != kSerialError; } 69 | inline bool IsActive() { return IsOpen(); } 70 | inline void SetOutput(FILE *f) { output = f; } 71 | 72 | int Open(char *filepath=NULL); 73 | void Close(); 74 | int Flush(); 75 | int Select(__darwin_suseconds_t usec=4000); 76 | int Read(char *buffer, int maxlen); 77 | int ReadLine(char *buffer, int maxlen, __darwin_suseconds_t usec=4000); 78 | int Write(char *buffer, int length); 79 | int WriteString(char *string); 80 | int BytesOnPort(); 81 | 82 | int ReInit(TabletSettings *sett); 83 | bool SetParameters(TabletSettings *sett); 84 | bool SetParameters(speed_t speed, tcflag_t databits, int parity, int stopbits, bool cts=false, bool dsr=false); 85 | bool SetDefaultParameters(); 86 | 87 | inline bool SetSpeed(speed_t s) { openSpeed = s; return ApplySettings(); } 88 | inline bool SetDataBits(tcflag_t d) { openDataBits = d; return ApplySettings(); } 89 | inline bool SetParity(int p) { openParity = p; return ApplySettings(); } 90 | inline bool SetStopBits(int s) { openStopBits = s; return ApplySettings(); } 91 | inline bool SetCTS(bool b) { openCTS = b; return ApplySettings(); } 92 | inline bool SetDSR(bool b) { openDSR = b; return ApplySettings(); } 93 | bool ApplySettings(); 94 | 95 | inline char* Name() { return shortName; } 96 | inline speed_t Speed() { return openSpeed; } 97 | inline tcflag_t DataBits() { return openDataBits; } 98 | inline int Parity() { return openParity; } 99 | inline int StopBits() { return openStopBits; } 100 | inline bool CTS() { return openCTS; } 101 | inline bool DSR() { return openDSR; } 102 | 103 | bool HasValidIterator(); 104 | void EndPortScan(); 105 | kern_return_t BeginPortScan(bool RS232Only=false); 106 | kern_return_t GetNextPortPath(); 107 | bool OpenNextMatchingPort(char *portname=NULL); 108 | }; 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /daemon/TabletSettings.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * TabletSettings.cpp 3 | * 4 | * TabletMagicDaemon 5 | * Thinkyhead Software 6 | * 7 | * This program is a component of TabletMagic. See the 8 | * accompanying documentation for more details about the 9 | * TabletMagic project. 10 | * 11 | * LICENSE 12 | * 13 | * This program is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU Library General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 2 of the License, or (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Library General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU Library General Public 24 | * License along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 | */ 27 | 28 | #include "TabletSettings.h" 29 | 30 | //=================================================================== 31 | // TabletSettings 32 | //=================================================================== 33 | 34 | #define straddf(x, s) sprintf(tmp,x,s); strcat(q, tmp) 35 | #define onebitval(x) ((mask>>x)&1); 36 | #define twobitval(x) ((mask>>x)&3); 37 | #define onebit(x, y) ((y&1)< 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | const char *known_machines[] = KNOWN_MACHINES; 19 | 20 | char* get_digitizer_string(void) { 21 | char *cmd, *tmp; 22 | 23 | // Find a digitizer in the IO Registry 24 | cmd = "ioreg -l | grep -A15 -E \"\\+-o (DIGI|WACM|COMA)\" | grep -m1 \\\"name\\\" | sed -E \"s/.*<\\\"?([^\\\">]+)\\\"?>/\\\\1/\""; 25 | char *digitizer_string = run_tool(cmd); 26 | 27 | if (digitizer_string != NULL) { 28 | // If not found then try an alternative method 29 | if (strlen(digitizer_string) == 0) { 30 | cmd = "ioreg -l | grep -E \"\\\"name\\\" = <\\\"(WAC|FUJ|FPI|574143|46554a|465049)[0-9A-F]+\\\">\" | sed -E \"s/.*<\\\"?([^\\\">]+)\\\"?>/\\\\1/\""; 31 | tmp = digitizer_string; 32 | digitizer_string = run_tool(cmd); 33 | free(tmp); 34 | } 35 | } 36 | 37 | // asprintf(&digitizer_string, "WACF005"); // FOR TESTING ONLY! 38 | 39 | // If we got a digitizer string, continue 40 | if (digitizer_string != NULL) { 41 | clean_string(digitizer_string); 42 | 43 | // If the string was very long, convert hex to decimal 44 | if (strlen(digitizer_string) > 12) { 45 | (void)asprintf(&cmd, "echo %s | xxd -r -p", digitizer_string); 46 | tmp = digitizer_string; 47 | digitizer_string = run_tool(cmd); 48 | clean_string(digitizer_string); 49 | free(tmp); 50 | free(cmd); 51 | } 52 | } 53 | 54 | return digitizer_string; 55 | } 56 | 57 | char is_known_machine(char **machine_string_ptr) { 58 | char is_known_mac = 0; 59 | char *machine_string = NULL; 60 | 61 | const char *machine_key = "hw.model"; 62 | size_t size = 0; 63 | (void)sysctlbyname(machine_key, NULL, &size, NULL, 0); 64 | 65 | if (size > 0) { 66 | machine_string = (char*)malloc(size); 67 | (void)sysctlbyname(machine_key, machine_string, &size, NULL, 0); 68 | 69 | #if !FORCE_TABLETPC 70 | 71 | // Test for a known mac platform 72 | int i; 73 | for (i=sizeof(known_machines)/sizeof(known_machines[0]); i--;) { 74 | if (!strncmp(machine_string, known_machines[i], strlen(known_machines[i]))) { 75 | is_known_mac = 1; 76 | break; 77 | } 78 | } 79 | 80 | #endif 81 | } 82 | 83 | if (machine_string_ptr == NULL) 84 | free(machine_string); 85 | else 86 | *machine_string_ptr = machine_string; 87 | 88 | 89 | return is_known_mac; 90 | } 91 | 92 | // Run tool and return the result, or null 93 | // Caller is responsible for freeing the result 94 | char* run_tool(char *cmd) { 95 | char *commandOut = NULL; 96 | 97 | FILE *pipe = popen(cmd, "r"); 98 | 99 | if (pipe != NULL) { 100 | commandOut = malloc(100); 101 | commandOut[0] = '\0'; 102 | (void)fgets(commandOut, 100, pipe); 103 | pclose(pipe); 104 | } 105 | 106 | return commandOut; 107 | } 108 | 109 | void clean_string(char *string) { 110 | int len = (int)strlen(string); 111 | 112 | while (len-- && (string[len] == '\n' || string[len] == '\r')) 113 | string[len] = '\0'; 114 | } 115 | -------------------------------------------------------------------------------- /helper/Digitizers.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Digitizers.h 3 | * 4 | * TabletMagic 5 | * Thinkyhead Software 6 | * 7 | * Utility functions to help retrieve a digitizer string from the IO Registry 8 | */ 9 | 10 | #define KNOWN_MACHINES {"AAPL","iMac","PowerBook","PowerMac","RackMac","Macmini","MacPro","MacBookPro","MacBook"} 11 | 12 | char* get_digitizer_string(void); 13 | char* run_tool(char *cmd); 14 | void clean_string(char *string); 15 | char is_known_machine(char **machine_string); 16 | -------------------------------------------------------------------------------- /helper/LaunchHelper.c: -------------------------------------------------------------------------------- 1 | /** 2 | * LaunchHelper.c 3 | * 4 | * TabletMagic 5 | * Thinkyhead Software 6 | * 7 | * This helper executable is used by the Preference Pane to: 8 | * (no arguments) Just SUID the LaunchHelper binary 9 | * "launchd" Create a LaunchD entry (which may be 'Disabled=YES') 10 | * "launchd10.5" Create a LaunchD entry suitable for Leopard 11 | * "disable" Delete the StartupItem 12 | * "enabletabletpc" Hack the serial driver plist to enable the digitizer 13 | * "getdigitizer" Return the digitizer code, if any 14 | * (other) Create a StartupItem using the passed arguments 15 | */ 16 | 17 | #include "Digitizers.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | int set_suid_root(char *path); 32 | 33 | #define LAUNCHER "com.thinkyhead.TabletMagic.plist" 34 | #define SRC "/tmp/" 35 | #define DSTD "/Library/LaunchDaemons" 36 | #define DSTA "/Library/LaunchAgents" 37 | 38 | #define STARTSRC "TabletMagicStarter" 39 | #define STARTDST "/Library/StartupItems/TabletMagic" 40 | #define STARTITEM "TabletMagic" 41 | 42 | #define KEXTDIR "/System/Library/Extensions/Apple16X50Serial.kext/Contents/PlugIns/Apple16X50ACPI.kext/Contents/" 43 | 44 | int main(int argc, char *argv[]) { 45 | int result = EX_OK; 46 | char *dst, *cmd; 47 | char *buff1, *buff2; 48 | struct stat st; 49 | int file; 50 | ssize_t size, filesize; 51 | 52 | if (geteuid() != 0) { 53 | fprintf(stderr, "LaunchHelper must be run as root!\n"); 54 | return EX_NOPERM; 55 | } 56 | 57 | // always make this binary suid root 58 | result = set_suid_root(argv[0]); 59 | 60 | if (argc == 2) { 61 | 62 | if (0 == strcmp(argv[1], "enabletabletpc")) { 63 | 64 | // Find a digitizer in the IO Registry 65 | cmd = "ioreg -l | grep -A15 -E \"\\+-o (DIGI|WACM|COMA)\" | grep -m1 \\\"name\\\" | sed -E \"s/.*<\\\"?([^\\\">]+)\\\"?>/\\\\1/\""; 66 | char *digitizer_string = get_digitizer_string(); 67 | 68 | // If we got a digitizer string, continue 69 | if (digitizer_string && strlen(digitizer_string)) { 70 | // Get the original digitizer string from the KEXT (usually "PNP0501") 71 | cmd = "defaults read " KEXTDIR "/Info IOKitPersonalities | grep IONameMatch | sed -e \"s/[ \\\\t]*IONameMatch = \\([^;]*\\);/\\\\1/\""; 72 | char *orig = run_tool(cmd); 73 | clean_string(orig); 74 | 75 | // Replace the string and put the results in a temporary file 76 | asprintf(&cmd, "sed -e \"s/%s/%s/g\" " KEXTDIR "/Info.plist >/tmp/digifix.tmp", orig, digitizer_string); 77 | result = system(cmd); 78 | free(cmd); 79 | 80 | free(orig); 81 | 82 | // Copy the original file to a backup on the Desktop 83 | result = system("cp " KEXTDIR "/Info.plist ~/Desktop/Info-`date +%Y%m%d%H%M%S`.plist"); 84 | 85 | // Replace the original plist 86 | result = rename("/tmp/digifix.tmp", KEXTDIR "/Info.plist"); 87 | 88 | // On success clear the extension cache and return the digitizer code 89 | if (strlen(digitizer_string) > 0) { 90 | result = remove("/System/Library/Extensions.mkext"); 91 | printf("%s", digitizer_string); 92 | } 93 | else 94 | printf("none"); 95 | } 96 | else 97 | printf("fail"); 98 | 99 | } 100 | else { 101 | // For other ops always remove the existing startup item 102 | result = system("rm -Rf " STARTDST); 103 | 104 | if (0 == strcmp(argv[1], "disable")) { 105 | // do nothing at all 106 | } 107 | else if (0 == strcmp(argv[1], "launchd") || 0 == strcmp(argv[1], "launchd10.5")) { 108 | // Install the LaunchD item (placed in /tmp before invocation) 109 | char *dir, *src = SRC LAUNCHER; 110 | 111 | if (0 == strcmp(argv[1], "launchd10.5")) { 112 | dir = DSTA; 113 | dst = DSTA "/" LAUNCHER; 114 | } else { 115 | dir = DSTD; 116 | dst = DSTD "/" LAUNCHER; 117 | } 118 | 119 | result = mkdir(dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); // 755 120 | result = remove(DSTA "/" LAUNCHER); 121 | result = remove(DSTD "/" LAUNCHER); 122 | result = rename(src, dst); 123 | result = chown(dst, 0, 0); 124 | result = chmod(dst, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); // 644 125 | } 126 | else { 127 | // Copy our template into StartupItems 128 | result = asprintf(&cmd, "cp -Rf %s/%s %s", dirname(argv[0]), STARTSRC, STARTDST); 129 | result = system(cmd); free(cmd); 130 | 131 | // Alter the startup script, adding our parameters 132 | file = open(STARTDST "/" STARTITEM, O_RDONLY|O_EXLOCK, 0); 133 | if (file != -1) { 134 | if (0 == fstat(file, &st)) { 135 | filesize = (int)st.st_size; 136 | 137 | buff1 = (char*)malloc(filesize+1); 138 | size = read(file, buff1, filesize); 139 | buff1[filesize] = '\0'; 140 | result = close(file); 141 | 142 | if (asprintf(&buff2, buff1, argv[1]) > filesize) { 143 | file = open(STARTDST "/" STARTITEM, O_WRONLY|O_EXLOCK, 0); 144 | size = write(file, buff2, strlen(buff2)); 145 | result = close(file); 146 | free(buff2); 147 | } 148 | 149 | free(buff1); 150 | } 151 | } 152 | 153 | // Set owners of the contents to root:wheel 154 | result = system("chown -Rf root:wheel " STARTDST); 155 | 156 | // Set permissions on the contents to 755 157 | result = system("chmod -Rf 755 " STARTDST); 158 | 159 | // Set permissions on all file resources to 644 160 | result = system("chmod -Rf 644 " STARTDST "/" "StartupParameters.plist " STARTDST "/Resources/*/*.strings"); 161 | } 162 | } 163 | } 164 | 165 | return result; 166 | } 167 | 168 | int set_suid_root(char *path) { 169 | struct stat st; 170 | int fd_tool; 171 | 172 | /* Open tool exclusively, so no one can change it while we bless it */ 173 | fd_tool = open(path, O_NONBLOCK|O_RDONLY|O_EXLOCK, 0); 174 | 175 | if (fd_tool == -1) 176 | return -4; 177 | 178 | if (fstat(fd_tool, &st)) 179 | return -5; 180 | 181 | if (st.st_uid != 0) { 182 | if (0 == fchown(fd_tool, 0, 0xFFFFFFFF) 183 | && 0 == fchmod(fd_tool, S_ISUID|S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) 184 | fprintf(stderr, "LaunchHelper is now SUID root!\n"); 185 | } 186 | 187 | close(fd_tool); 188 | 189 | return 0; 190 | } 191 | -------------------------------------------------------------------------------- /prefpane/English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | CFBundleName = "TabletMagic"; 4 | CFBundleShortVersionString = "2.0.0"; 5 | CFBundleGetInfoString = "TabletMagic Version 2.0.0, Copyright (c) 2022 Thinkyhead Software"; 6 | NSHumanReadableCopyright = "Copyright (c) 2022 Thinkyhead Software"; 7 | 8 | -------------------------------------------------------------------------------- /prefpane/English.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Kill Sheet */ 2 | "Kill TabletMagicDaemon?" = "Kill TabletMagicDaemon?"; 3 | "This will kill the TabletMagicDaemon process. Click the Enabled checkbox to start it up again." = "This will kill the TabletMagicDaemon process. Click the Enabled checkbox to start it up again."; 4 | "Kill It!" = "Kill It!"; 5 | "Cancel" = "Cancel"; 6 | 7 | /* Port and Tablet */ 8 | "Automatic" = "Automatic"; 9 | "Daemon Not Running" = "Daemon Not Running"; 10 | "Starting Daemon..." = "Starting Daemon..."; 11 | "Looking for a tablet..." = "Looking for a tablet..."; 12 | "SD Fallback" = "SD Fallback"; 13 | "No Tablet Found" = "No Tablet Found"; 14 | "Unknown" = "Unknown"; 15 | 16 | /* Mapping Pane */ 17 | "Untitled Preset" = "Untitled Preset"; 18 | "Custom" = "Custom"; 19 | "Version %@" = "Version %@"; 20 | "max" = "max"; 21 | "all" = "all"; 22 | "< constrain <" = "< constrain <"; 23 | "Are you sure you want to delete the preset \"%@\" ?" = "Are you sure you want to delete the preset \"%@\" ?"; 24 | 25 | /* Testing Pane */ 26 | "Datastream (%@ %@)" = "Datastream (%@ %@)"; 27 | "Binary" = "Binary"; 28 | "ASCII" = "ASCII"; 29 | 30 | /* TabletPC Sheets */ 31 | "Enable TabletPC Digitizer?" = "Enable TabletPC Digitizer?"; 32 | "This will modify a core system component to enable your digitizer, if possible." = "This will modify a core system component to enable your digitizer, if possible."; 33 | "Modify and Reboot" = "Modify and Reboot"; 34 | "No Digitizer Found!" = "No Digitizer Found!"; 35 | "Sorry, but the enabler couldn't find a digitizer in the I/O Registry." = "Sorry, but the enabler couldn't find a digitizer in the I/O Registry."; 36 | "Sorry, but the enabler failed to execute." = "Sorry, but the enabler failed to execute."; 37 | "Okay" = "Okay"; 38 | 39 | /* Commands Menu */ 40 | "Do Self-Test" = "Do Self-Test"; 41 | "Get Model & ROM Version" = "Get Model & ROM Version"; 42 | "Get Maximum Coordinates" = "Get Maximum Coordinates"; 43 | "Get Current Settings" = "Get Current Settings"; 44 | "Get Setting M1" = "Get Setting M1"; 45 | "Get Setting M2" = "Get Setting M2"; 46 | "Start" = "Start"; 47 | "Stop" = "Stop"; 48 | "Get Tablet Info" = "Get Tablet Info"; 49 | "Sample at 133pps" = "Sample at 133pps"; 50 | "Sample at 80pps" = "Sample at 80pps"; 51 | "Sample at 40pps" = "Sample at 40pps"; 52 | "Reset to Bit Pad Two" = "Reset to Bit Pad Two"; 53 | "Reset to MM1201" = "Reset to MM1201"; 54 | "Reset to WACOM II-S" = "Reset to WACOM II-S"; 55 | "Reset to WACOM IV" = "Reset to WACOM IV"; 56 | "Reset to Defaults of Mode" = "Reset to Defaults of Mode"; 57 | "Enable Tilt Mode" = "Enable Tilt Mode"; 58 | "Disable Tilt Mode" = "Disable Tilt Mode"; 59 | "Suppressed Mode (IN2)" = "Suppressed Mode (IN2)"; 60 | "Point Mode" = "Point Mode"; 61 | "Switch Stream Mode" = "Switch Stream Mode"; 62 | "Stream Mode" = "Stream Mode"; 63 | "Continuous Data Mode" = "Continuous Data Mode"; 64 | "Trailing Data Mode" = "Trailing Data Mode"; 65 | "Normal Data Mode" = "Normal Data Mode"; 66 | "Origin UL" = "Origin UL"; 67 | "Origin LL" = "Origin LL"; 68 | "Scale 15240 x 15240" = "Scale 15240 x 15240"; 69 | "Scale 32768 x 32768" = "Scale 32768 x 32768"; 70 | "Enable Pressure Mode" = "Enable Pressure Mode"; 71 | "Disable Pressure Mode" = "Disable Pressure Mode"; 72 | "ASCII Data Mode" = "ASCII Data Mode"; 73 | "Binary Data Mode" = "Binary Data Mode"; 74 | "Enable Relative Mode" = "Enable Relative Mode"; 75 | "Disable Relative Mode" = "Disable Relative Mode"; 76 | "Set 1000p/i Resolution" = "Set 1000p/i Resolution"; 77 | "Set 50p/mm Resolution" = "Set 50p/mm Resolution"; 78 | "Enable All Menu Buttons" = "Enable All Menu Buttons"; 79 | "Disable Setup Button" = "Disable Setup Button"; 80 | "Disable Function Buttons" = "Disable Function Buttons"; 81 | "Disable Pressure Buttons" = "Disable Pressure Buttons"; 82 | "Pressure Buttons as Macros" = "Pressure Buttons as Macros"; 83 | "BA Command" = "BA Command"; 84 | "LA Command" = "LA Command"; 85 | "CA Command" = "CA Command"; 86 | "OR Command" = "OR Command"; 87 | "RC Command" = "RC Command"; 88 | "RS Command" = "RS Command"; 89 | "SB Command" = "SB Command"; 90 | "YR Command" = "YR Command"; 91 | "AS Command" = "AS Command"; 92 | "DE Command" = "DE Command"; 93 | "IC Command" = "IC Command"; 94 | "PH Command" = "PH Command"; 95 | "SC Command" = "SC Command"; 96 | 97 | 98 | /* Tablet Events */ 99 | "Pen Engaged" = "Pen Engaged"; 100 | "Pen Disengaged" = "Pen Disengaged"; 101 | "Pen Down" = "Pen Down"; 102 | "Pen Up" = "Pen Up"; 103 | "Eraser Engaged" = "Eraser Engaged"; 104 | "Eraser Disengaged" = "Eraser Disengaged"; 105 | "Eraser Down" = "Eraser Down"; 106 | "Eraser Up" = "Eraser Up"; 107 | "Button Click" = "Button Click"; 108 | "Button Release" = "Button Release"; 109 | 110 | -------------------------------------------------------------------------------- /prefpane/English.lproj/TabletMagicSearchGroups.searchTerms: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tabletmagicMain 6 | 7 | localizableStrings 8 | 9 | 10 | index 11 | wacom, tablet, digitizer, serial, ink 12 | title 13 | TabletMagic 14 | 15 | 16 | 17 | tabletmagicSetupTab 18 | 19 | localizableStrings 20 | 21 | 22 | index 23 | wacom, tablet, setup, serial, origin, pressure, tilt, drawing, ink 24 | title 25 | TabletMagic Setup 26 | 27 | 28 | 29 | tabletmagicMappingTab 30 | 31 | localizableStrings 32 | 33 | 34 | index 35 | mapping, geometry, screen, buttons 36 | title 37 | TabletMagic Mapping 38 | 39 | 40 | 41 | tabletmagicTestingTab 42 | 43 | localizableStrings 44 | 45 | 46 | index 47 | test, try, monitor, log, logging, commands 48 | title 49 | TabletMagic Testing 50 | 51 | 52 | 53 | tabletmagicExtrasTab 54 | 55 | localizableStrings 56 | 57 | 58 | index 59 | ink, daemon, tabletmagicdaemon, kill, reset 60 | title 61 | TabletMagic Extras 62 | 63 | 64 | 65 | tabletmagicDonateTab 66 | 67 | localizableStrings 68 | 69 | 70 | index 71 | donate, github, oss, gpl 72 | title 73 | TabletMagic Donation 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /prefpane/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 2.0b20 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 2.0.0 23 | NSMainNibFile 24 | TabletMagicPref 25 | NSPrefPaneIconFile 26 | TabletMagicPref.tiff 27 | NSPrefPaneIconLabel 28 | TabletMagic 29 | NSPrefPaneSearchParameters 30 | TabletMagicSearchGroups 31 | NSPrincipalClass 32 | TabletMagicPref 33 | NSSupportsSuddenTermination 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /prefpane/Resources/PrefPaneTitle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkyhead/TabletMagic/3a067906765c82e063e61dede24fc0104fc79453/prefpane/Resources/PrefPaneTitle.png -------------------------------------------------------------------------------- /prefpane/Resources/TabletMagicPref.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkyhead/TabletMagic/3a067906765c82e063e61dede24fc0104fc79453/prefpane/Resources/TabletMagicPref.tiff -------------------------------------------------------------------------------- /prefpane/Resources/TabletMagicStarter/Resources/Dutch.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Starting TabletMagic 6 | 'TabletMagic' wordt gestart 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /prefpane/Resources/TabletMagicStarter/Resources/English.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Starting TabletMagic 6 | Starting TabletMagic 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /prefpane/Resources/TabletMagicStarter/Resources/French.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Starting TabletMagic 6 | Démarrage de TabletMagic 7 | 8 | 9 | -------------------------------------------------------------------------------- /prefpane/Resources/TabletMagicStarter/Resources/German.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Starting TabletMagic 6 | "TabletMagic" wird gestartet 7 | 8 | 9 | -------------------------------------------------------------------------------- /prefpane/Resources/TabletMagicStarter/Resources/Italian.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Starting TabletMagic 6 | Avvio TabletMagic 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /prefpane/Resources/TabletMagicStarter/Resources/Japanese.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Starting TabletMagic 6 | TabletMagic を起動中 7 | 8 | 9 | -------------------------------------------------------------------------------- /prefpane/Resources/TabletMagicStarter/Resources/Spanish.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Starting TabletMagic 6 | Iniciando TabletMagic 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /prefpane/Resources/TabletMagicStarter/StartupParameters.plist: -------------------------------------------------------------------------------- 1 | { 2 | Description = "TabletMagic Daemon"; 3 | Messages = {start = "Starting TabletMagic"; stop = "Stopping TabletMagic"; }; 4 | Preference = Late; 5 | Provides = (TabletMagic); 6 | Requires = ("System Log"); 7 | } -------------------------------------------------------------------------------- /prefpane/Resources/TabletMagicStarter/TabletMagic: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## 4 | # TabletMagic 5 | ## 6 | 7 | . /etc/rc.common 8 | 9 | StartService () { 10 | TMPATH=/Library/PreferencePanes/TabletMagic.prefPane/Contents/Resources/TabletMagicDaemon 11 | 12 | ConsoleMessage "Starting TabletMagic" 13 | if [ -x $TMPATH ]; then 14 | $TMPATH %s 15 | fi 16 | } 17 | 18 | StopService () { 19 | ConsoleMessage "Stopping TabletMagic" 20 | killall TabletMagicDaemon 21 | } 22 | 23 | RestartService () { 24 | StopService 25 | sleep 1 26 | StartService 27 | } 28 | 29 | RunService "$1" 30 | -------------------------------------------------------------------------------- /prefpane/Resources/TabletPCEnabler.sh: -------------------------------------------------------------------------------- 1 | # 2 | # TabletPCEnabler.sh ($Id: TabletPCEnabler.sh,v 1.3 2008/07/31 16:28:24 slurslee Exp $) 3 | # 4 | # Used by TabletMagic to enable the serial port of a TabletPC 5 | # 6 | 7 | # 8 | # Get the digitizer name from ioreg -l (or -lx) 9 | # 10 | DIGI=`ioreg -l | grep -A15 -E "\+-o (DIGI|WACM|COMA)" | grep -m1 \"name\" | sed -E "s/.*<\"?([^\">]+)\"?>/\\1/"` 11 | if [ "$DIGI" == "" ]; then 12 | DIGI=`ioreg -l | grep -E "\"name\" = <\"(WAC|FUJ|574143|46554a)[0-9A-F]+\">" | sed -E "s/.*<\"?([^\">]+)\"?>/\\1/"` 13 | fi 14 | 15 | if [ "$DIGI" == "" ]; then 16 | # 17 | # return "notfound" value - no digitizer hardware! 18 | # 19 | echo "none" 20 | exit 21 | fi 22 | 23 | # 24 | # Translate a hex coded string into ASCII 25 | # 26 | if [ ${#DIGI} -gt 12 ]; then 27 | DIGI=`echo $DIGI | xxd -r -p` 28 | fi 29 | 30 | # 31 | # Enter the kernel extension directory 32 | # 33 | cd /System/Library/Extensions/Apple16X50Serial.kext/Contents/PlugIns/Apple16X50ACPI.kext/Contents/ 34 | 35 | # 36 | # Make sure the proper key exists 37 | # 38 | OLDNAME=`defaults read $PWD/Info IOKitPersonalities | grep IONameMatch | sed -e "s/[ \\t]*IONameMatch = \([^;]*\);/\\1/"` 39 | 40 | # 41 | # Replace the IONameMatch value for the serial kext 42 | # 43 | sed -e "s/$OLDNAME/$DIGI/g" Info.plist >/tmp/digifix.tmp 44 | mv -f /tmp/digifix.tmp /Users/Shared/Info.plist 45 | 46 | # 47 | # Fix the file's permissions! 48 | # 49 | chown root:wheel Info.plist 50 | chmod 644 Info.plist 51 | 52 | # 53 | # Delete the kernel cache 54 | # 55 | rm /System/Library/Extensions.mkext 56 | 57 | # 58 | # return the digitizer string 59 | # 60 | echo $DIGI 61 | -------------------------------------------------------------------------------- /prefpane/Resources/button.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkyhead/TabletMagic/3a067906765c82e063e61dede24fc0104fc79453/prefpane/Resources/button.jpg -------------------------------------------------------------------------------- /prefpane/Resources/trigger-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkyhead/TabletMagic/3a067906765c82e063e61dede24fc0104fc79453/prefpane/Resources/trigger-off.png -------------------------------------------------------------------------------- /prefpane/Resources/trigger-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkyhead/TabletMagic/3a067906765c82e063e61dede24fc0104fc79453/prefpane/Resources/trigger-on.png -------------------------------------------------------------------------------- /prefpane/TMAreaChooser.h: -------------------------------------------------------------------------------- 1 | /** 2 | * TMAreaChooser.h 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | enum { 9 | DRAG_NONE, 10 | DRAG_TOPLEFT, 11 | DRAG_TOPRIGHT, 12 | DRAG_BOTTOMLEFT, 13 | DRAG_BOTTOMRIGHT, 14 | DRAG_WHOLE 15 | }; 16 | 17 | @interface TMAreaChooser : NSView { 18 | id controller; 19 | int dragType; 20 | NSPoint dragStart; 21 | NSRect originalFrame; 22 | float constrainW, constrainH; 23 | BOOL isConstrained; 24 | 25 | float maxWidth, maxHeight; 26 | float scaleFactorW, scaleFactorH; 27 | float left, top, right, bottom; 28 | 29 | IBOutlet NSButton *buttonAll; 30 | IBOutlet NSTextField *textBottom; 31 | IBOutlet NSTextField *textLeft; 32 | IBOutlet NSTextField *textRight; 33 | IBOutlet NSTextField *textSizeHeading; 34 | IBOutlet NSTextField *textTop; 35 | } 36 | 37 | // Actions 38 | - (IBAction)boundsChanged:(id)sender; 39 | - (IBAction)setToMaxSize:(id)sender; 40 | - (IBAction)setToLess:(id)sender; 41 | - (IBAction)setToMore:(id)sender; 42 | 43 | // Methods 44 | - (void)constrain:(NSSize)size; 45 | - (void)disableConstrain; 46 | 47 | - (void)drawSubsections:(NSRect)rect; 48 | 49 | - (void)setAreaWithRect:(NSRect)rect; 50 | - (void)setAreaLeft:(float)l top:(float)t right:(float)r bottom:(float)b; 51 | - (void)setAreaFromEditFields; 52 | - (void)setMaxWidth:(unsigned)w height:(unsigned)h; 53 | - (void)updateMaxWidth:(unsigned)w height:(unsigned)h; 54 | - (void)setFromPresetWidth:(float)w height:(float)h left:(float)l top:(float)t right:(float)r bottom:(float)b; 55 | - (void)resetToAll; 56 | - (void)presetChanged; 57 | 58 | - (unsigned)left; 59 | - (unsigned)top; 60 | - (unsigned)right; 61 | - (unsigned)bottom; 62 | - (unsigned)maxWidth; 63 | - (unsigned)maxHeight; 64 | - (NSSize)representedSize; 65 | - (NSSize)activeArea; 66 | - (BOOL)isConstrained; 67 | - (NSRect)sanityCheckArea:(NSRect)areaRect; 68 | - (NSRect)activeRect; 69 | 70 | - (void)updateView:(BOOL)doView andText:(BOOL)doText; 71 | - (void)updateTextFields; 72 | 73 | - (NSPoint)repPointFromViewPoint:(NSPoint)viewPoint; 74 | - (NSPoint)viewPointFromRepPoint:(NSPoint)repPoint; 75 | 76 | - (void)drawHandlePart:(NSRect)rect asActive:(BOOL)active; 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /prefpane/TMAreaChooser.m: -------------------------------------------------------------------------------- 1 | /** 2 | * TMAreaChooser.m 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | #import "TMAreaChooser.h" 9 | #import "TMPresetsController.h" 10 | #import "TabletMagicPref.h" 11 | #import "../common/Constants.h" 12 | 13 | #define HandleSize 4 14 | #define HSize2 (HandleSize*2+1) 15 | 16 | 17 | @implementation TMAreaChooser 18 | 19 | // 20 | // Language Notes: 21 | // 22 | // initWithFrame as an initializer returns an instance of TMAreaChooser. 23 | // Note that it doesn't call alloc. Presumably the root class calls the 24 | // alloc method and initializers just call their superclass counterpart. 25 | // 26 | 27 | - (id)initWithFrame:(NSRect)frameRect { 28 | if ((self = [super initWithFrame:frameRect]) != nil) { 29 | // Add initialization code here 30 | originalFrame = [ self frame ]; 31 | isConstrained = NO; 32 | constrainW = constrainH = 1.0f; 33 | } 34 | return self; 35 | } 36 | 37 | #pragma mark - 38 | 39 | - (void)constrain:(NSSize)size { 40 | if (size.width < size.height) { 41 | constrainW = size.width / size.height; 42 | constrainH = 1.0f; 43 | } 44 | else { 45 | constrainW = 1.0; 46 | constrainH = size.height / size.width; 47 | } 48 | 49 | isConstrained = YES; 50 | [ self setAreaLeft:left top:top right:right bottom:bottom ]; 51 | [ buttonAll setTitle:[ thePane localizedString:@"max" ] ]; 52 | } 53 | 54 | - (void)disableConstrain { 55 | isConstrained = NO; 56 | constrainW = constrainH = 1.0; 57 | [ self setNeedsDisplay:YES ]; 58 | [ buttonAll setTitle:[ thePane localizedString:@"all" ] ]; 59 | } 60 | 61 | - (void)setAreaWithRect:(NSRect)rect { 62 | [ self setAreaLeft:rect.origin.x top:rect.origin.y right:rect.origin.x+rect.size.width bottom:rect.origin.y+rect.size.height ]; 63 | } 64 | 65 | // Set the area with spatial coordinates 66 | - (void)setAreaLeft:(float)l top:(float)t right:(float)r bottom:(float)b { 67 | // NSLog(@"setAreaLeft %f %f %f %f", l, t, r, b); 68 | 69 | NSRect newRect = [ self sanityCheckArea:NSMakeRect(l, t, r - l, b - t) ]; 70 | l = newRect.origin.x; 71 | t = newRect.origin.y; 72 | r = newRect.origin.x + newRect.size.width; 73 | b = newRect.origin.y + newRect.size.height; 74 | 75 | if (isConstrained) { 76 | float w = r - l, h = b - t; 77 | if (constrainH == 1.0f) 78 | w = h * constrainW; 79 | else 80 | h = w * constrainH; 81 | 82 | switch(dragType) { 83 | case DRAG_TOPLEFT: 84 | l = r - w; 85 | t = b - h; 86 | break; 87 | case DRAG_TOPRIGHT: 88 | r = l + w; 89 | t = b - h; 90 | break; 91 | case DRAG_BOTTOMLEFT: 92 | l = r - w; 93 | b = t + h; 94 | break; 95 | case DRAG_BOTTOMRIGHT: 96 | r = l + w; 97 | b = t + h; 98 | break; 99 | default: { 100 | float nl = (l + r - w) / 2.0; 101 | float nt = (t + b - h) / 2.0; 102 | float nr = (l + r + w) / 2.0; 103 | float nb = (t + b + h) / 2.0; 104 | l = nl; 105 | t = nt; 106 | r = nr; 107 | b = nb; 108 | } 109 | } 110 | } 111 | 112 | newRect = [ self sanityCheckArea:NSMakeRect(l, t, r - l, b - t) ]; 113 | left = newRect.origin.x; 114 | top = newRect.origin.y; 115 | right = left + newRect.size.width; 116 | bottom = top + newRect.size.height; 117 | 118 | [ self updateView:YES andText:YES ]; 119 | } 120 | 121 | - (void)setAreaFromEditFields { 122 | float l = [ textLeft floatValue ]; 123 | float t = [ textTop floatValue ]; 124 | float r = [ textRight floatValue ]; 125 | float b = [ textBottom floatValue ]; 126 | 127 | if (l < 0.0f || l >= maxWidth) l = left; 128 | if (t < 0.0f || t >= maxHeight) t = top; 129 | if (r < 0.0f || r >= maxWidth) r = right; 130 | if (b < 0.0f || b >= maxHeight) b = bottom; 131 | 132 | if (floorf(l) != floorf(left) || floorf(t) != floorf(top) || floorf(r) != floorf(right) || floorf(b) != floorf(bottom)) { 133 | [ self setAreaLeft:l top:t right:r bottom:b ]; 134 | [ self presetChanged ]; 135 | } 136 | } 137 | 138 | // 139 | // setMaxWidth:height: 140 | // Set the width and height represented by this control 141 | // 142 | // If the width and height are the same then the whole control 143 | // is used as the active region. Otherwise a proportional area 144 | // of the control is made active. 145 | // 146 | - (void)setMaxWidth:(unsigned)w height:(unsigned)h; { 147 | [ textSizeHeading setStringValue:[ NSString stringWithFormat:@"%d x %d", w, h ] ]; 148 | 149 | maxWidth = (float)w; 150 | maxHeight = (float)h; 151 | 152 | float ratioW, ratioH; 153 | 154 | if (maxWidth > maxHeight) { 155 | ratioW = 1.0; 156 | ratioH = maxHeight / maxWidth; 157 | } else if (maxWidth < maxHeight) { 158 | ratioW = maxWidth / maxHeight; 159 | ratioH = 1.0; 160 | } 161 | else 162 | ratioW = ratioH = 1.0; 163 | 164 | // The active width and height in NSView units 165 | float activeWidth = floorf(originalFrame.size.width * ratioW + 0.5f); 166 | float activeHeight = floorf(originalFrame.size.height * ratioH + 0.5f); 167 | 168 | // Number of units represented by each pixel 169 | // These will tend to be very close due to the proportional stuff 170 | scaleFactorW = maxWidth / activeWidth; 171 | scaleFactorH = maxHeight / activeHeight; 172 | 173 | if ([ thePane systemVersionAtLeastMajor:10 minor:3 ]) 174 | [ self setHidden:YES ]; 175 | 176 | // Make the control size match the proportions 177 | [ self setFrame:NSMakeRect( 178 | originalFrame.origin.x + (originalFrame.size.width - activeWidth) / 2.0f, 179 | originalFrame.origin.y + (originalFrame.size.height - activeHeight) / 2.0f, 180 | activeWidth, activeHeight) ]; 181 | 182 | if ([ thePane systemVersionAtLeastMajor:10 minor:3 ]) 183 | [ self setHidden:NO ]; 184 | 185 | [ self setNeedsDisplay:YES ]; 186 | } 187 | 188 | 189 | /* 190 | When the resolution changes the maxWidth and height 191 | need to be updated, but also the 192 | */ 193 | - (void)updateMaxWidth:(unsigned)w height:(unsigned)h { 194 | // NSLog(@"updateMaxWidth %f %f", w, h); 195 | 196 | float divW = (float)w / maxWidth, 197 | divH = (float)h / maxHeight; 198 | 199 | if (divW != 1.0 || divH != 1.0) { 200 | [ self setMaxWidth:w height:h ]; 201 | [ self setAreaLeft:left*divW top:top*divH right:right*divW bottom:bottom*divH ]; 202 | } 203 | 204 | } 205 | 206 | 207 | /* 208 | When you set this control from a preset, the preset data 209 | may be based on a different max width and height. So use 210 | this to make sure the values are properly translated from 211 | the original coordinate system to the current one. 212 | */ 213 | - (void)setFromPresetWidth:(float)w height:(float)h left:(float)l top:(float)t right:(float)r bottom:(float)b { 214 | float divW = maxWidth / w, 215 | divH = maxHeight / h; 216 | 217 | // NSLog(@"setFromPresetWidth (%f %f vs %f %f) : %f %f %f %f", w, h, maxWidth, maxHeight, l, t, r, b); 218 | 219 | [ self setAreaLeft:l*divW top:t*divH right:r*divW bottom:b*divH ]; 220 | } 221 | 222 | - (void)resetToAll { 223 | float l = 0, t = 0, r = maxWidth - 1, b = maxHeight - 1; 224 | 225 | if (isConstrained) { 226 | if (constrainW == 1.0) { 227 | float m = top + bottom; 228 | float q = maxWidth * constrainH; 229 | t = (m - q) / 2.0f; 230 | b = (m + q) / 2.0f; 231 | } 232 | else { 233 | float m = left + right; 234 | float q = maxHeight * constrainW; 235 | l = (m - q) / 2.0f; 236 | r = (m + q) / 2.0f; 237 | } 238 | } 239 | 240 | [ self setAreaLeft:l top:t right:r bottom:b ]; 241 | } 242 | 243 | - (void)presetChanged { 244 | [ (TMPresetsController*)controller presetChanged:self ]; 245 | } 246 | 247 | #pragma mark - Class Overrides 248 | 249 | - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { return YES; } 250 | 251 | - (void)drawSubsections:(NSRect)rect {} 252 | 253 | // 254 | // drawRect:rect 255 | // The draw method. 256 | // 257 | - (void)drawRect:(NSRect)rect { 258 | [ NSColor setIgnoresAlpha:NO ]; 259 | 260 | [[NSColor controlBackgroundColor] setFill]; 261 | NSRectFill(rect); 262 | 263 | NSPoint lt = { left, top }; 264 | NSPoint rb = { right, bottom }; 265 | lt = [ self viewPointFromRepPoint:lt ]; 266 | rb = [ self viewPointFromRepPoint:rb ]; 267 | float l = floorf(lt.x+0.5f), t = floorf(lt.y+0.5f), r = floorf(rb.x+0.5f), b = floorf(rb.y+0.5f); 268 | 269 | NSRect innerRect = { { l, rect.size.height - b }, { r - l, b - t } }; 270 | NSRect tlRect = { { l - HandleSize, rect.size.height - t - HandleSize }, { HSize2, HSize2 } }; 271 | NSRect trRect = { { r - HandleSize - 1, rect.size.height - t - HandleSize }, { HSize2, HSize2 } }; 272 | NSRect blRect = { { l - HandleSize, rect.size.height - b - HandleSize }, { HSize2, HSize2 } }; 273 | NSRect brRect = { { r - HandleSize - 1, rect.size.height - b - HandleSize }, { HSize2, HSize2 } }; 274 | 275 | if (dragType == DRAG_WHOLE) 276 | [[NSColor colorWithCalibratedRed:0.92 green:0.92 blue:0.98 alpha:0.5] setFill]; 277 | else 278 | [[NSColor colorWithCalibratedRed:0.96 green:0.96 blue:0.99 alpha:0.5] setFill]; 279 | 280 | NSRectFill(innerRect); 281 | 282 | [[NSColor colorWithCalibratedRed:0.8 green:0.8 blue:0.90 alpha:1.0] setFill]; 283 | NSFrameRect(innerRect); 284 | 285 | [ self drawHandlePart:tlRect asActive:dragType == DRAG_TOPLEFT || dragType == DRAG_WHOLE ]; 286 | [ self drawHandlePart:trRect asActive:dragType == DRAG_TOPRIGHT || dragType == DRAG_WHOLE ]; 287 | [ self drawHandlePart:blRect asActive:dragType == DRAG_BOTTOMLEFT || dragType == DRAG_WHOLE ]; 288 | [ self drawHandlePart:brRect asActive:dragType == DRAG_BOTTOMRIGHT || dragType == DRAG_WHOLE ]; 289 | 290 | [ self drawSubsections:rect ]; 291 | 292 | [[NSColor blackColor] setFill]; 293 | NSFrameRectWithWidth(rect, 1.0f); 294 | } 295 | 296 | - (void)mouseDown:(NSEvent *)theEvent { 297 | NSPoint lpos = [ self convertPoint:[ theEvent locationInWindow ] fromView:nil ]; 298 | 299 | // Convert the view point to its represented point 300 | NSRect bounds = [ self bounds ]; 301 | lpos.y = bounds.size.height - lpos.y; 302 | NSPoint realpos = [ self repPointFromViewPoint:lpos ]; 303 | 304 | int c = DRAG_NONE; 305 | 306 | float hw = HandleSize * scaleFactorW, hh = HandleSize * scaleFactorH; 307 | 308 | if (realpos.x > left-hw && realpos.x <= left+hw) { 309 | if (realpos.y > top-hh && realpos.y <= top+hh) 310 | c = DRAG_TOPLEFT; 311 | else if (realpos.y > bottom-hh && realpos.y <= bottom+hh) 312 | c = DRAG_BOTTOMLEFT; 313 | } 314 | else if (realpos.x > right-hw && realpos.x <= right+hw) { 315 | if (realpos.y > top-hh && realpos.y <= top+hh) 316 | c = DRAG_TOPRIGHT; 317 | else if (realpos.y > bottom-hh && realpos.y <= bottom+hh) 318 | c = DRAG_BOTTOMRIGHT; 319 | } 320 | 321 | if (c == DRAG_NONE && realpos.x > left && realpos.x < right && realpos.y > top && realpos.y < bottom) 322 | c = DRAG_WHOLE; 323 | 324 | dragStart = realpos; 325 | dragType = c; 326 | 327 | [ self updateView:YES andText:YES ]; 328 | 329 | // return (dragType != DRAG_NONE); 330 | } 331 | 332 | - (void)mouseDragged:(NSEvent *)theEvent { 333 | if (dragType == DRAG_NONE) 334 | return; 335 | 336 | NSPoint lpos = [ self convertPoint:[ theEvent locationInWindow ] fromView:nil ]; 337 | 338 | // Convert the view point to its represented point 339 | NSRect bounds = [ self bounds ]; 340 | lpos.y = bounds.size.height - lpos.y; 341 | NSPoint realpos = [ self repPointFromViewPoint:lpos ]; 342 | 343 | float dx = realpos.x - dragStart.x, dy = realpos.y - dragStart.y; 344 | dragStart = realpos; 345 | 346 | float l = left, t = top, r = right, b = bottom; 347 | 348 | // 349 | // Dragging the whole box 350 | // 351 | if (dragType == DRAG_WHOLE) { 352 | // Move all corners by the same amount 353 | l += dx; 354 | r += dx; 355 | t += dy; 356 | b += dy; 357 | 358 | // And constrain the outer bounds 359 | if (l < 0) { 360 | r += (0 - l); 361 | l = 0; 362 | } else if (r > maxWidth-1) { 363 | l += (maxWidth-1 - r); 364 | r = maxWidth-1; 365 | } 366 | 367 | if (t < 0) { 368 | b += (0 - t); 369 | t = 0; 370 | } else if (b > maxHeight-1) { 371 | t += (maxHeight-1 - b); 372 | b = maxHeight-1; 373 | } 374 | 375 | // Draw 376 | 377 | } 378 | else { 379 | 380 | float mx = 15 * scaleFactorW, my = 15 * scaleFactorH; 381 | 382 | // Corner right or left 383 | if (dragType == DRAG_TOPLEFT || dragType == DRAG_BOTTOMLEFT) { 384 | l += dx; 385 | if (l < 0) l = 0; 386 | else if (l > r - mx) l = r - mx; 387 | } 388 | else { 389 | r += dx; 390 | if (r > maxWidth-1) r = maxWidth-1; 391 | else if (r < l + mx) r = l + mx; 392 | } 393 | 394 | // Corner bottom or top 395 | if (dragType == DRAG_TOPLEFT || dragType == DRAG_TOPRIGHT) { 396 | t += dy; 397 | if (t < 0) t = 0; 398 | else if (t > b - my) t = b - my; 399 | } 400 | else { 401 | b += dy; 402 | if (b > maxHeight-1) b = maxHeight-1; 403 | else if (b < t + my) b = t + my; 404 | } 405 | 406 | // UpdateRepFromPix 407 | // ConstrainCorner corn 408 | // UpdatePixFromRep 409 | 410 | } 411 | 412 | [ self setAreaLeft:l top:t right:r bottom:b ]; 413 | } 414 | 415 | - (void)mouseUp:(NSEvent *)theEvent { 416 | if (dragType != DRAG_NONE) { 417 | dragType = DRAG_NONE; 418 | [ self updateView:YES andText:YES ]; 419 | [ self presetChanged ]; 420 | } 421 | } 422 | 423 | #pragma mark - 424 | 425 | // NOTE: the Y part should be inverted before calling this 426 | - (NSPoint)repPointFromViewPoint:(NSPoint)viewPoint { 427 | NSPoint repPoint = { viewPoint.x * scaleFactorW, viewPoint.y * scaleFactorH }; 428 | return repPoint; 429 | } 430 | 431 | // NOTE: The returned Y value is inverted 432 | - (NSPoint)viewPointFromRepPoint:(NSPoint)repPoint { 433 | NSPoint viewPoint = { repPoint.x / scaleFactorW, repPoint.y / scaleFactorH }; 434 | return viewPoint; 435 | } 436 | 437 | - (NSRect)sanityCheckArea:(NSRect)areaRect { 438 | float l = areaRect.origin.x, 439 | t = areaRect.origin.y, 440 | r = l + areaRect.size.width, 441 | b = t + areaRect.size.height; 442 | 443 | if (r < l) { 444 | float q = l; 445 | l = r; r = q; 446 | } 447 | 448 | if (b < t) { 449 | float q = t; 450 | t = b; b = q; 451 | } 452 | 453 | // Sanity check all values 454 | if (l < 0.0f) { r -= l; l = 0.0f; } 455 | if (l > maxWidth) { r -= (l - maxWidth + 1.0f); l = maxWidth - 1.0f; } 456 | if (t < 0.0f) { b -= t; t = 0.0f; } 457 | if (t >= maxHeight) { b -= (t - maxHeight + 1.0f); t = maxHeight - 1.0f; } 458 | if (r < 0.0f) { l -= r; r = 0.0f; } 459 | if (r >= maxWidth) { l -= (r - maxWidth + 1.0f); r = maxWidth - 1.0f; } 460 | if (b < 0.0f) { t -= b; b = 0.0f; } 461 | if (b >= maxHeight) { t -= (b - maxHeight + 1.0f); b = maxHeight - 1.0f; } 462 | 463 | if (l < 0.0f) l = 0.0f; 464 | if (l >= maxWidth) l = maxWidth - 1.0f; 465 | if (t < 0.0f) t = 0.0f; 466 | if (t >= maxHeight) t = maxHeight - 1.0f; 467 | if (r < 0.0f) r = 0.0f; 468 | if (r >= maxWidth) r = maxWidth - 1.0f; 469 | if (b < 0.0f) b = 0.0f; 470 | if (b >= maxHeight) b = maxHeight - 1.0f; 471 | 472 | return NSMakeRect(l, t, r - l, b - t); 473 | } 474 | 475 | - (void)updateView:(BOOL)doView andText:(BOOL)doText { 476 | if (doView) 477 | [ self setNeedsDisplay:YES ]; 478 | 479 | if (doText) 480 | [ self updateTextFields ]; 481 | } 482 | 483 | - (void)updateTextFields { 484 | [ textLeft setIntValue:(int)floorf(left) ]; 485 | [ textTop setIntValue:(int)floorf(top) ]; 486 | [ textRight setIntValue:(int)floorf(right) ]; 487 | [ textBottom setIntValue:(int)floorf(bottom) ]; 488 | } 489 | 490 | - (void)drawHandlePart:(NSRect)rect asActive:(BOOL)active { 491 | NSColor *fillColor; 492 | 493 | if (active) { 494 | fillColor = isConstrained 495 | ? [NSColor colorWithCalibratedRed:0.6 green:0.6 blue:0.9 alpha:1.0] 496 | : [NSColor colorWithCalibratedRed:0.4 green:0.8 blue:0.4 alpha:1.0]; 497 | } 498 | else { 499 | fillColor = isConstrained 500 | ? [NSColor colorWithCalibratedRed:0.8 green:0.8 blue:1.0 alpha:1.0] 501 | : [NSColor colorWithCalibratedRed:0.8 green:1.0 blue:0.8 alpha:1.0]; 502 | } 503 | 504 | [ fillColor setFill ]; 505 | 506 | NSBezierPath *bez = [ NSBezierPath bezierPathWithOvalInRect:rect ]; 507 | [ bez fill ]; 508 | 509 | [[NSColor colorWithCalibratedRed:0.4 green:0.7 blue:0.8 alpha:1.0] setStroke]; 510 | [ bez stroke ]; 511 | } 512 | 513 | #pragma mark - Accessors 514 | 515 | - (unsigned)left { return (unsigned)left; } 516 | - (unsigned)top { return (unsigned)top; } 517 | - (unsigned)right { return (unsigned)right; } 518 | - (unsigned)bottom { return (unsigned)bottom; } 519 | - (unsigned)maxWidth { return (unsigned)maxWidth; } 520 | - (unsigned)maxHeight { return (unsigned)maxHeight; } 521 | - (BOOL)isConstrained { return isConstrained; } 522 | 523 | - (NSSize)representedSize { return NSMakeSize( maxWidth, maxHeight ); } 524 | - (NSSize)activeArea { return NSMakeSize(right - left, bottom - top); } 525 | - (NSRect)activeRect { return NSMakeRect(left, top, right - left, bottom - top); } 526 | 527 | 528 | #pragma mark - Actions 529 | 530 | - (IBAction)setToMaxSize:(id)sender { 531 | [ self resetToAll ]; 532 | [ self presetChanged ]; 533 | } 534 | 535 | - (IBAction)setToLess:(id)sender { 536 | float w = right - left - 20 * scaleFactorW; 537 | float h = bottom - top - 20 * scaleFactorH; 538 | if (w < 15 * scaleFactorW) w = 15 * scaleFactorW; 539 | if (h < 15 * scaleFactorH) h = 15 * scaleFactorH; 540 | 541 | NSRect oldRect = [ self activeRect ]; 542 | NSRect newRect = NSInsetRect(oldRect, (oldRect.size.width-w)/2.0f, (oldRect.size.height-h)/2.0f); 543 | [ self setAreaWithRect:[ self sanityCheckArea:newRect ] ]; 544 | [ self presetChanged ]; 545 | } 546 | 547 | - (IBAction)setToMore:(id)sender { 548 | [ self setAreaWithRect:[ self sanityCheckArea:NSInsetRect([ self activeRect ], -10*scaleFactorW, -10*scaleFactorH) ] ]; 549 | [ self presetChanged ]; 550 | } 551 | 552 | - (IBAction)boundsChanged:(id)sender { 553 | [ self setAreaFromEditFields ]; 554 | } 555 | 556 | @end 557 | -------------------------------------------------------------------------------- /prefpane/TMAreaChooserScreen.h: -------------------------------------------------------------------------------- 1 | /** 2 | * TMAreaChooserScreen.h 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | #import "TMAreaChooser.h" 9 | 10 | @interface TMAreaChooserScreen : TMAreaChooser { 11 | float minX, minY, maxX, maxY; 12 | } 13 | 14 | - (void)calibrate:(BOOL)bReset; 15 | - (void)drawSubsections:(NSRect)rect; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /prefpane/TMAreaChooserScreen.m: -------------------------------------------------------------------------------- 1 | /** 2 | * TMAreaChooserScreen.m 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | #import "TMAreaChooserScreen.h" 9 | #import "TMPresetsController.h" 10 | #import "../common/Constants.h" 11 | 12 | @implementation TMAreaChooserScreen 13 | 14 | - (void)setAreaLeft:(float)l top:(float)t right:(float)r bottom:(float)b { 15 | [ super setAreaLeft:l top:t right:r bottom:b ]; 16 | 17 | if ([ controller tabletIsConstrained ]) 18 | [ controller setTabletConstraint:[ self activeArea ] ]; 19 | } 20 | 21 | - (void)drawSubsections:(NSRect)rect { 22 | NSArray *screenArray = [ NSScreen screens ]; 23 | int i, count = (int)[ screenArray count ]; 24 | 25 | if (count > 1) { 26 | for (i=0; i maxX) maxX = r; 67 | if (b > maxY) maxY = b; 68 | } 69 | 70 | if (bReset) { 71 | // NSLog(@"Initializing chooser based on screen %f %f", maxX - minX + 1, maxY - minY + 1 ); 72 | [ self setMaxWidth:maxX - minX + 1 height:maxY - minY + 1 ]; 73 | [ self setAreaLeft:minX top:minY right:maxX bottom:maxY ]; 74 | } 75 | else { 76 | // NSLog(@"Recalibrating chooser based on screen"); 77 | [ self updateMaxWidth:maxX - minX + 1 height:maxY - minY + 1 ]; 78 | } 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /prefpane/TMAreaChooserTablet.h: -------------------------------------------------------------------------------- 1 | /** 2 | * TMAreaChooserTablet.h 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | #import "TMAreaChooser.h" 9 | 10 | @interface TMAreaChooserTablet : TMAreaChooser { 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /prefpane/TMAreaChooserTablet.m: -------------------------------------------------------------------------------- 1 | /** 2 | * TMAreaChooserTablet.m 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | #import "TMAreaChooserTablet.h" 9 | 10 | @implementation TMAreaChooserTablet 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /prefpane/TMController.h: -------------------------------------------------------------------------------- 1 | /** 2 | * TMController.h 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | @class TMScratchpad, TMPresetsController; 9 | 10 | @interface TMController : NSObject { 11 | 12 | NSDistributedNotificationCenter *ncenter; 13 | NSPort *mPort; 14 | CFMessagePortRef cfPortIn; 15 | CFMessagePortRef cfPortOut; 16 | NSString *bundleID; 17 | AuthorizationRef fAuthorization; 18 | BOOL tabletEnabled; 19 | BOOL autoLaunchEnabled; 20 | NSTimer *settingTimer, *scaleTimer, *autoStartTimer; 21 | NSTimer *streamTimer, *killTimer, *pingTimer; 22 | BOOL modelUD, modelCT, modelSD, modelPL, modelGD, modelPC; 23 | BOOL ignore_next_info; 24 | int stream_reply_size; 25 | int stream_reply_count; 26 | BOOL hackintosh; 27 | BOOL scale_from_stylus; 28 | int current_tab; 29 | 30 | IBOutlet NSTabView *tabview; 31 | 32 | // Top controls 33 | IBOutlet NSPopUpButton *popupSerialPort; 34 | IBOutlet NSTextField *textTabletInfo; 35 | IBOutlet NSTextField *textVersion; 36 | IBOutlet NSButton *checkEnabled; 37 | 38 | // Memory bank controls 39 | IBOutlet NSMatrix *matrixMem; 40 | IBOutlet NSButtonCell *cellMem0; 41 | IBOutlet NSButtonCell *cellMem1; 42 | IBOutlet NSButtonCell *cellMem2; 43 | IBOutlet NSButton *buttonSetBank; 44 | 45 | // Serial connection controls 46 | IBOutlet NSPopUpButton *popupBaud; 47 | IBOutlet NSPopUpButton *popupDataBits; 48 | IBOutlet NSPopUpButton *popupParity; 49 | IBOutlet NSPopUpButton *popupStopBits; 50 | IBOutlet NSButton *checkCTS; 51 | IBOutlet NSButton *checkDSR; 52 | 53 | // Settings controls 54 | IBOutlet NSPopUpButton *popupCommandSet; 55 | IBOutlet NSPopUpButton *popupOutputFormat; 56 | IBOutlet NSPopUpButton *popupCoordSys; 57 | IBOutlet NSPopUpButton *popupTerminator; 58 | IBOutlet NSPopUpButton *popupOrigin; 59 | IBOutlet NSPopUpButton *popupReadHeight; 60 | IBOutlet NSPopUpButton *popupSensitivity; 61 | IBOutlet NSPopUpButton *popupTransferMode; 62 | IBOutlet NSPopUpButton *popupTransferRate; 63 | IBOutlet NSPopUpButton *popupResolution; 64 | IBOutlet NSButton *checkTilt; 65 | IBOutlet NSButton *checkMultiMode; 66 | IBOutlet NSButton *checkPlugPlay; 67 | IBOutlet NSButton *checkOORData; 68 | IBOutlet NSTextField *editIncrement; 69 | IBOutlet NSTextField *editInterval; 70 | IBOutlet NSTextField *editXRez; 71 | IBOutlet NSTextField *editYRez; 72 | IBOutlet NSTextField *editXScale; 73 | IBOutlet NSTextField *editYScale; 74 | IBOutlet NSStepper *stepperIncrement; 75 | IBOutlet NSStepper *stepperInterval; 76 | IBOutlet NSStepper *stepperXRez; 77 | IBOutlet NSStepper *stepperYRez; 78 | IBOutlet NSStepper *stepperXScale; 79 | IBOutlet NSStepper *stepperYScale; 80 | 81 | IBOutlet NSBox *groupMemory; 82 | IBOutlet NSBox *groupSerial; 83 | IBOutlet NSBox *groupProtocol; 84 | IBOutlet NSBox *groupDigitizer; 85 | 86 | // Data stream and commands 87 | IBOutlet NSBox *groupDatastream; 88 | IBOutlet NSTextField *textDatastream; 89 | IBOutlet NSPopUpButton *popupCommands; 90 | IBOutlet NSButton *buttonSendCommand; 91 | 92 | // Tablet data rates 93 | IBOutlet NSTextField *textRateBytes; 94 | IBOutlet NSTextField *textRatePackets; 95 | 96 | // Tablet data interpreted 97 | IBOutlet NSTextField *textPosX; 98 | IBOutlet NSTextField *textPosY; 99 | IBOutlet NSTextField *textTiltX; 100 | IBOutlet NSTextField *textTiltY; 101 | IBOutlet NSTextField *textEvent; 102 | IBOutlet NSTextField *textPressure; 103 | IBOutlet NSButton *buttonView1; 104 | IBOutlet NSButton *buttonView2; 105 | IBOutlet NSButton *buttonView3; 106 | IBOutlet NSButton *buttonView4; 107 | IBOutlet NSProgressIndicator *progPressure; 108 | 109 | // A scratch pad to draw inside 110 | IBOutlet TMScratchpad *scratchPad; 111 | IBOutlet NSColorWell *colorPen; 112 | IBOutlet NSColorWell *colorEraser; 113 | IBOutlet NSSlider *sliderFlowPen; 114 | IBOutlet NSSlider *sliderFlowEraser; 115 | 116 | // Geometry controls 117 | IBOutlet TMPresetsController *presetsController; 118 | 119 | IBOutlet NSPopUpButton *popupStylusTip; 120 | IBOutlet NSPopUpButton *popupBarrelSwitch1; 121 | IBOutlet NSPopUpButton *popupBarrelSwitch2; 122 | IBOutlet NSPopUpButton *popupEraser; 123 | 124 | IBOutlet NSButton *checkMouseMode; 125 | IBOutlet NSSlider *sliderMouseScaling; 126 | 127 | IBOutlet NSButton *checkDonation; 128 | 129 | // Extras 130 | IBOutlet NSBox *groupAutoStart; 131 | IBOutlet NSButton *checkAutoStart; 132 | IBOutlet NSButton *buttonInk; 133 | IBOutlet NSButton *buttonKill; 134 | IBOutlet NSButton *buttonPanic; 135 | 136 | // TabletPC 137 | IBOutlet NSButton *buttonEnableDigitizer; 138 | IBOutlet NSButton *checkTabletPC; 139 | IBOutlet NSButton *checkGetFromStylus; 140 | IBOutlet NSTextField *textTweakScaleX; 141 | IBOutlet NSTextField *textTweakScaleY; 142 | } 143 | 144 | // Interface Actions 145 | - (IBAction)toggledDaemon:(id)sender; 146 | - (IBAction)selectedSerialPort:(id)sender; 147 | - (IBAction)chooseMemoryBank:(id)sender; 148 | - (IBAction)activateMem:(id)sender; 149 | - (IBAction)settingsChanged:(id)sender; 150 | - (IBAction)serialSettingsChanged:(id)sender; 151 | - (IBAction)toggledTiltOrMM:(id)sender; 152 | - (IBAction)actionIncrement:(id)sender; 153 | - (IBAction)actionInterval:(id)sender; 154 | - (IBAction)actionRezX:(id)sender; 155 | - (IBAction)actionRezY:(id)sender; 156 | - (IBAction)actionScaleX:(id)sender; 157 | - (IBAction)actionScaleY:(id)sender; 158 | 159 | // Testing Actions 160 | - (IBAction)sendSelectedCommand:(id)sender; 161 | 162 | // Extras Actions 163 | - (IBAction)toggleAutoStart:(id)sender; 164 | - (IBAction)enableInk:(id)sender; 165 | - (IBAction)killTheDaemon:(id)sender; 166 | - (IBAction)panicButton:(id)sender; 167 | 168 | // TabletPC Actions 169 | - (BOOL)detectTabletPC; 170 | - (IBAction)enableDigitizer:(id)sender; 171 | - (IBAction)toggledTabletPC:(id)sender; 172 | - (IBAction)toggledGetFromStylus:(id)sender; 173 | - (IBAction)tweakScaleChanged:(id)sender; 174 | - (void)expandScaleX:(int)x y:(int)y; 175 | - (void)handleEnablerResponse:(char *)reply; 176 | - (void)hackDialogEnded:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo; 177 | - (void)failDialogEnded:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo; 178 | 179 | // Convenience methods 180 | - (BOOL)setValueOfControl:(id)control toInt:(int)value; 181 | - (void)setText:(id)control andStepper:(id)control2 toInt:(int)value; 182 | - (NSString*)GetStartupArgsAndDaemonize:(BOOL)daemonize; 183 | 184 | // Incoming Messages 185 | 186 | #if ASYNCHRONOUS_MESSAGES 187 | - (CFDataRef)handleMessageFromPort:(CFMessagePortRef)loc withData:(CFDataRef)data andInfo:(void*)info; 188 | #endif 189 | 190 | - (void)handleDaemonMessageData:(CFDataRef)data; 191 | - (void)handleDaemonMessage:(char*)message; 192 | 193 | // Outgoing Messages 194 | - (CFMessagePortRef)getRemoteMessagePort; 195 | - (BOOL)remotePortExists; 196 | - (void)disposeRemoteMessagePort; 197 | - (void)remoteMessagePortWentAway; 198 | - (void)sendNSStringToDaemon:(NSString*)string; 199 | - (void)sendMessageToDaemon:(char*)message; 200 | - (CFDataRef)sendRequestToDaemon:(char*)message; 201 | 202 | // A timer to ping the daemon every 1/2 second 203 | - (void)doPingTimer:(NSTimer*)theTimer; 204 | 205 | // Stream timer 206 | - (void)startStreamIfShowing; 207 | - (void)setStreamMonitorEnabled:(BOOL)enable; 208 | - (void)doStreamTimer:(NSTimer*)theTimer; 209 | 210 | // Superclass overrides 211 | - (void)mainViewDidLoad; 212 | - (void)paneTerminating; 213 | - (void) paneDidSelect; 214 | - (void)paneWillUnselect; 215 | 216 | // Preferences 217 | - (void)loadPreferences; 218 | - (void)savePreferences; 219 | 220 | // Authorization 221 | - (void)setupAuthorization; 222 | - (void)cleanUpAuthorization; 223 | - (BOOL)isFileSuidRoot:(char*)fullpath; 224 | 225 | // Daemon control 226 | - (BOOL)startDaemon; 227 | - (BOOL)killDaemon; 228 | - (BOOL)isDaemonLoaded:(BOOL)refresh; 229 | - (OSStatus)updateAutoStart; 230 | - (void)updateAutoStartSoon; 231 | - (void)doAutoStartTimer:(NSTimer*)theTimer; 232 | - (char*)runLaunchHelper:(NSString*)argsString; 233 | 234 | // Controls 235 | - (void)requestCurrentSettings; 236 | - (void)setControlsForSettings:(char*)settings; 237 | - (void)setStreamHeadingForSet:(int)set andFormat:(int)fmt; 238 | - (void)setControlsForCommandSet; 239 | - (void)setControlsForConnect:(BOOL)connected; 240 | - (void)updatePortPopup; 241 | - (void)updateAutoStartCheckbox; 242 | - (NSArray *)getSerialPorts; 243 | - (void)selectPortByName:(NSString*)portName; 244 | 245 | // Donate Tab Methods 246 | - (IBAction)donate:(id)sender; 247 | - (IBAction)visit:(id)sender; 248 | 249 | // A timer to delay settings for 1/2 second 250 | - (void)doSettingsTimer:(NSTimer*)theTimer; 251 | - (void)doScaleTimer:(NSTimer*)theTimer; 252 | 253 | - (void)forgetTabletInfo; 254 | 255 | - (void)scaleChanged; 256 | - (void)screenChanged; 257 | 258 | - (NSImage*)retainedHighlightedImageForImage:(NSImage*)image; 259 | 260 | - (void)killDialogEnded:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo; 261 | 262 | - (char*)getCStringFromString:(NSString*)string; 263 | 264 | @end 265 | 266 | extern TMController *theController; 267 | -------------------------------------------------------------------------------- /prefpane/TMPreset.h: -------------------------------------------------------------------------------- 1 | /** 2 | * TMPReset.h 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | @interface TMPreset : NSObject { 9 | NSString *name; 10 | int tabletLeft, tabletTop, tabletRight, tabletBottom; 11 | int tabletRangeX, tabletRangeY; 12 | int screenLeft, screenTop, screenRight, screenBottom; 13 | int screenWidth, screenHeight; 14 | int buttonTip, buttonSwitch1, buttonSwitch2, buttonEraser; 15 | BOOL mouseMode; 16 | float mouseScaling; 17 | BOOL constrained; 18 | } 19 | 20 | - (void)setTabletRangeX:(int)x y:(int)y; 21 | - (void)setScreenWidth:(int)x height:(int)y; 22 | - (void)setTabletAreaLeft:(float)l top:(float)t right:(float)r bottom:(float)b; 23 | - (void)setScreenAreaLeft:(float)l top:(float)t right:(float)r bottom:(float)b; 24 | - (void)setMappingForTip:(int)tip side1:(int)s1 side2:(int)s2 eraser:(int)e; 25 | 26 | - (void)initProperties; 27 | - (char*)daemonMessage; 28 | - (char*)mouseModeMessage; 29 | 30 | // Preset as a dictionary 31 | - (id)initWithDictionary:(NSDictionary*)dict; 32 | - (NSDictionary*) dictionary; 33 | 34 | // Matching clauses 35 | -(BOOL)matchesTabletLeft:(int)tl top:(int)tt right:(int)tr bottom:(int)tb; 36 | -(BOOL)matchesScreenLeft:(int)sl top:(int)st right:(int)sr bottom:(int)sb; 37 | -(BOOL)matchesButtonTip:(int)b0 switch1:(int)b1 switch2:(int)b2 eraser:(int)be; 38 | -(BOOL)matchesMouseMode:(BOOL)mm scaling:(float)ms; 39 | 40 | // Accessors 41 | - (NSString*)name; 42 | - (int)tabletRangeX; 43 | - (int)tabletRangeY; 44 | - (int)tabletLeft; 45 | - (int)tabletTop; 46 | - (int)tabletRight; 47 | - (int)tabletBottom; 48 | - (int)screenWidth; 49 | - (int)screenHeight; 50 | - (int)screenLeft; 51 | - (int)screenTop; 52 | - (int)screenRight; 53 | - (int)screenBottom; 54 | - (int)buttonTip; 55 | - (int)buttonSwitch1; 56 | - (int)buttonSwitch2; 57 | - (int)buttonEraser; 58 | - (BOOL)mouseMode; 59 | - (float)mouseScaling; 60 | - (BOOL)constrained; 61 | 62 | // Setters 63 | - (void)setName:(NSString *)name; 64 | - (void)setTabletRangeX:(int)n; 65 | - (void)setTabletRangeY:(int)n; 66 | - (void)setTabletLeft:(int)n; 67 | - (void)setTabletTop:(int)n; 68 | - (void)setTabletRight:(int)n; 69 | - (void)setTabletBottom:(int)n; 70 | - (void)setScreenWidth:(int)n; 71 | - (void)setScreenHeight:(int)n; 72 | - (void)setScreenLeft:(int)n; 73 | - (void)setScreenTop:(int)n; 74 | - (void)setScreenRight:(int)n; 75 | - (void)setScreenBottom:(int)n; 76 | - (void)setButtonTip:(int)n; 77 | - (void)setButtonSwitch1:(int)n; 78 | - (void)setButtonSwitch2:(int)n; 79 | - (void)setButtonEraser:(int)n; 80 | - (void)setMouseMode:(BOOL)n; 81 | - (void)setMouseScaling:(float)n; 82 | - (void)setConstrained:(BOOL)n; 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /prefpane/TMPreset.m: -------------------------------------------------------------------------------- 1 | /** 2 | * TMPreset.m 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | #import "TMPreset.h" 9 | #import "TMController.h" 10 | #import "TabletMagicPref.h" 11 | #import "../common/Constants.h" 12 | 13 | @implementation TMPreset 14 | 15 | - (id)init { 16 | if ((self = [super init])) { 17 | name = nil; 18 | [ self initProperties ]; 19 | } 20 | 21 | return self; 22 | } 23 | 24 | - (id)initWithDictionary:(NSDictionary*)dict { 25 | [ self initProperties ]; 26 | 27 | [ self setName:[dict objectForKey:@keyName] ]; 28 | 29 | tabletRangeX = [ [ dict objectForKey:@keyTabletRangeX ] intValue ]; 30 | tabletRangeY = [ [ dict objectForKey:@keyTabletRangeY ] intValue ]; 31 | 32 | tabletLeft = [ [ dict objectForKey:@keyTabletLeft ] intValue ]; 33 | tabletTop = [ [ dict objectForKey:@keyTabletTop ] intValue ]; 34 | tabletRight = [ [ dict objectForKey:@keyTabletRight ] intValue ]; 35 | tabletBottom = [ [ dict objectForKey:@keyTabletBottom ] intValue ]; 36 | 37 | screenWidth = [ [ dict objectForKey:@keyScreenWidth ] intValue ]; 38 | screenHeight = [ [ dict objectForKey:@keyScreenHeight ] intValue ]; 39 | 40 | screenLeft = [ [ dict objectForKey:@keyScreenLeft ] intValue ]; 41 | screenTop = [ [ dict objectForKey:@keyScreenTop ] intValue ]; 42 | screenRight = [ [ dict objectForKey:@keyScreenRight ] intValue ]; 43 | screenBottom = [ [ dict objectForKey:@keyScreenBottom ] intValue ]; 44 | 45 | buttonTip = [ [ dict objectForKey:@keyStylusTip ] intValue ]; 46 | buttonSwitch1 = [ [ dict objectForKey:@keySwitch1 ] intValue ]; 47 | buttonSwitch2 = [ [ dict objectForKey:@keySwitch2 ] intValue ]; 48 | buttonEraser = [ [ dict objectForKey:@keyEraser ] intValue ]; 49 | 50 | mouseMode = [ [ dict objectForKey:@keyMouseMode ] boolValue ]; 51 | mouseScaling = [ [ dict objectForKey:@keyMouseScaling ] floatValue ]; 52 | 53 | constrained = [ [ dict objectForKey:@keyConstrained ] boolValue ]; 54 | 55 | return self; 56 | } 57 | 58 | - (void)setTabletRangeX:(int)x y:(int)y { 59 | tabletRangeX = x; 60 | tabletRangeY = y; 61 | } 62 | 63 | - (void)setScreenWidth:(int)w height:(int)h { 64 | screenWidth = w; 65 | screenHeight = h; 66 | } 67 | 68 | - (void)setTabletAreaLeft:(float)l top:(float)t right:(float)r bottom:(float)b { 69 | tabletLeft = l; 70 | tabletTop = t; 71 | tabletRight = r; 72 | tabletBottom = b; 73 | } 74 | 75 | - (void)setScreenAreaLeft:(float)l top:(float)t right:(float)r bottom:(float)b { 76 | screenLeft = l; 77 | screenTop = t; 78 | screenRight = r; 79 | screenBottom = b; 80 | } 81 | 82 | - (void)setMappingForTip:(int)tip side1:(int)s1 side2:(int)s2 eraser:(int)e { 83 | buttonTip = tip; 84 | buttonSwitch1 = s1; 85 | buttonSwitch2 = s2; 86 | buttonEraser = e; 87 | } 88 | 89 | #pragma mark - 90 | 91 | -(BOOL)matchesTabletLeft:(int)tl top:(int)tt right:(int)tr bottom:(int)tb { 92 | return tabletLeft == tl 93 | && tabletTop == tt 94 | && tabletRight == tr 95 | && tabletBottom == tb; 96 | } 97 | 98 | -(BOOL)matchesScreenLeft:(int)sl top:(int)st right:(int)sr bottom:(int)sb { 99 | return screenLeft == sl 100 | && screenTop == st 101 | && screenRight == sr 102 | && screenBottom == sb; 103 | } 104 | 105 | -(BOOL)matchesButtonTip:(int)b0 switch1:(int)b1 switch2:(int)b2 eraser:(int)be { 106 | return buttonTip = b0 107 | && buttonSwitch1 == b1 108 | && buttonSwitch2 == b2 109 | && buttonEraser == be; 110 | } 111 | 112 | -(BOOL)matchesMouseMode:(BOOL)mm scaling:(float)ms { 113 | float md = mouseScaling - ms; 114 | return mouseMode==mm && md>-0.02 && md<0.02; 115 | } 116 | 117 | #pragma mark - 118 | 119 | - (void)initProperties { 120 | [ self setName:[ thePane localizedString:@"Untitled Preset" ] ]; 121 | 122 | tabletRangeX = k12inches1270ppi; 123 | tabletRangeY = k12inches1270ppi; 124 | tabletLeft = 0; 125 | tabletTop = 0; 126 | tabletRight = k12inches1270ppi-1; 127 | tabletBottom = k12inches1270ppi-1; 128 | 129 | screenWidth = 1600; 130 | screenHeight = 1200; 131 | screenLeft = 0; 132 | screenTop = 0; 133 | screenRight = 1599; 134 | screenBottom = 1199; 135 | 136 | buttonTip = kSystemButton1; 137 | buttonSwitch1 = kSystemButton1; 138 | buttonSwitch2 = kSystemButton2; 139 | buttonEraser = kSystemEraser; 140 | 141 | mouseMode = NO; 142 | mouseScaling = 1.0; 143 | 144 | constrained = NO; 145 | } 146 | 147 | - (char*)daemonMessage { 148 | static char message[200]; 149 | sprintf(message, "geom %d %d %d %d : %d %d %d %d : %d %d %d %d : %d %0.2f", 150 | tabletLeft, tabletTop, tabletRight, tabletBottom, 151 | screenLeft, screenTop, screenRight, screenBottom, 152 | buttonTip, buttonSwitch1, buttonSwitch2, buttonEraser, 153 | mouseMode, mouseScaling 154 | ); 155 | 156 | return message; 157 | } 158 | 159 | - (char*)mouseModeMessage { 160 | static char message[200]; 161 | sprintf(message, "mmode %d %.4f", mouseMode, mouseScaling); 162 | return message; 163 | } 164 | 165 | - (NSDictionary*)dictionary { 166 | static NSDictionary *dict = nil; 167 | 168 | if (dict) { 169 | #if !ARC_ENABLED 170 | [ dict release ]; 171 | #else 172 | dict = nil; 173 | #endif 174 | } 175 | 176 | NSArray * keys = [NSArray arrayWithObjects: 177 | @keyName, 178 | @keyScreenWidth, @keyScreenHeight, 179 | @keyScreenLeft, @keyScreenTop, @keyScreenRight, @keyScreenBottom, 180 | @keyTabletRangeX, @keyTabletRangeY, 181 | @keyTabletLeft, @keyTabletTop, @keyTabletRight, @keyTabletBottom, 182 | @keyStylusTip, @keySwitch1, @keySwitch2, @keyEraser, 183 | @keyMouseMode, @keyMouseScaling, 184 | @keyConstrained, 185 | nil]; 186 | 187 | NSArray * values = [NSArray arrayWithObjects: 188 | name, 189 | NSINT(screenWidth), NSINT(screenHeight), 190 | NSINT(screenLeft), NSINT(screenTop), NSINT(screenRight), NSINT(screenBottom), 191 | NSINT(tabletRangeX), NSINT(tabletRangeY), 192 | NSINT(tabletLeft), NSINT(tabletTop), NSINT(tabletRight), NSINT(tabletBottom), 193 | NSINT(buttonTip), NSINT(buttonSwitch1), NSINT(buttonSwitch2), NSINT(buttonEraser), 194 | NSBOOL(mouseMode), NSFLOAT(mouseScaling), 195 | NSBOOL(constrained), 196 | nil]; 197 | 198 | dict = [[NSDictionary alloc] initWithObjects:values forKeys:keys]; 199 | 200 | return dict; 201 | } 202 | 203 | #pragma mark - 204 | 205 | - (NSString*)name { return name; } 206 | - (int)tabletRangeX { return tabletRangeX; } 207 | - (int)tabletRangeY { return tabletRangeY; } 208 | - (int)tabletLeft { return tabletLeft; } 209 | - (int)tabletTop { return tabletTop; } 210 | - (int)tabletRight { return tabletRight; } 211 | - (int)tabletBottom { return tabletBottom; } 212 | - (int)screenWidth { return screenWidth; } 213 | - (int)screenHeight { return screenHeight; } 214 | - (int)screenLeft { return screenLeft; } 215 | - (int)screenTop { return screenTop; } 216 | - (int)screenRight { return screenRight; } 217 | - (int)screenBottom { return screenBottom; } 218 | - (int)buttonTip { return buttonTip; } 219 | - (int)buttonSwitch1 { return buttonSwitch1; } 220 | - (int)buttonSwitch2 { return buttonSwitch2; } 221 | - (int)buttonEraser { return buttonEraser; } 222 | - (BOOL)mouseMode { return mouseMode; } 223 | - (float)mouseScaling { return mouseScaling; } 224 | - (BOOL)constrained { return constrained; } 225 | 226 | #pragma mark - 227 | 228 | - (void)setName:(NSString *)n { 229 | #if !ARC_ENABLED 230 | [ name release ]; 231 | #endif 232 | name = [ n copy ]; 233 | } 234 | 235 | - (void)setTabletRangeX:(int)n { tabletRangeX = n; } 236 | - (void)setTabletRangeY:(int)n { tabletRangeY = n; } 237 | - (void)setTabletLeft:(int)n { tabletLeft = n; } 238 | - (void)setTabletTop:(int)n { tabletTop = n; } 239 | - (void)setTabletRight:(int)n { tabletRight = n; } 240 | - (void)setTabletBottom:(int)n { tabletBottom = n; } 241 | - (void)setScreenWidth:(int)n { screenWidth = n; } 242 | - (void)setScreenHeight:(int)n { screenHeight = n; } 243 | - (void)setScreenLeft:(int)n { screenLeft = n; } 244 | - (void)setScreenTop:(int)n { screenTop = n; } 245 | - (void)setScreenRight:(int)n { screenRight = n; } 246 | - (void)setScreenBottom:(int)n { screenBottom = n; } 247 | - (void)setButtonTip:(int)n { buttonTip = n; } 248 | - (void)setButtonSwitch1:(int)n { buttonSwitch1 = n; } 249 | - (void)setButtonSwitch2:(int)n { buttonSwitch2 = n; } 250 | - (void)setButtonEraser:(int)n { buttonEraser = n; } 251 | - (void)setMouseMode:(BOOL)n { mouseMode = n; } 252 | - (void)setMouseScaling:(float)n { mouseScaling = n; } 253 | - (void)setConstrained:(BOOL)n { constrained = n; } 254 | 255 | @end 256 | -------------------------------------------------------------------------------- /prefpane/TMPresetsController.h: -------------------------------------------------------------------------------- 1 | /** 2 | * TMPresetsController.h 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | * 7 | * This controller connects the Preset model to 8 | * the Mapping view and the main TMController. 9 | */ 10 | 11 | @class TMAreaChooserTablet, TMAreaChooserScreen, TMPreset; 12 | 13 | @interface TMPresetsController : NSObject { 14 | int activePresetIndex; 15 | NSMutableArray *presetsArray; 16 | TMPreset *activePreset; // the active preset, unarchived from the dictionary 17 | 18 | IBOutlet NSWindow *prefsWindow; 19 | IBOutlet NSWindow *sheetAdd; 20 | IBOutlet NSWindow *sheetDelete; 21 | IBOutlet NSWindow *sheetRename; 22 | 23 | IBOutlet NSButton *buttonAdd; 24 | IBOutlet NSButton *buttonDelete; 25 | IBOutlet NSButton *buttonRename; 26 | 27 | IBOutlet NSTextField *editAdd; 28 | IBOutlet NSTextField *editRename; 29 | IBOutlet NSTextField *textDelete; 30 | 31 | IBOutlet NSButton *checkMouseMode; 32 | 33 | IBOutlet NSPopUpButton *popupEraser; 34 | IBOutlet NSPopUpButton *popupPresets; 35 | IBOutlet NSPopUpButton *popupStylusTip; 36 | IBOutlet NSPopUpButton *popupSwitch1; 37 | IBOutlet NSPopUpButton *popupSwitch2; 38 | 39 | IBOutlet NSSlider *sliderScaling; 40 | 41 | IBOutlet TMAreaChooserTablet *chooserTablet; 42 | IBOutlet TMAreaChooserScreen *chooserScreen; 43 | IBOutlet NSButton *buttonConstrain; 44 | } 45 | 46 | // Initialization 47 | - (void)mainViewDidLoad; 48 | - (BOOL)apply2b8Patches; // 2b8 is a minor release to automate the new button mappings 49 | 50 | // Methods 51 | - (void)loadPresets; 52 | - (void)activatePresetIndex:(int)i; 53 | - (void)sendPresetToDaemon; 54 | - (void)sendMouseModeToDaemon; 55 | - (void)updatePresetFromControls; 56 | - (void)activatePresetMatching:(char*)geom; 57 | - (void)synchronizePresetInArray; 58 | - (void)geometryReceived:(char*)geom; 59 | - (void)reflectConstrainSetting:(BOOL)b; 60 | - (NSDictionary*)dictionary; 61 | 62 | - (void)initControls; 63 | - (void)updatePresetsMenu; 64 | - (void)updateControlsForActivePreset; 65 | - (void)screenChanged; 66 | 67 | - (void)setTabletRangeX:(unsigned)x y:(unsigned)y; 68 | - (void)updateTabletScaleX:(unsigned)x y:(unsigned)y; 69 | - (void)setScreenWidth:(unsigned)w height:(unsigned)h; 70 | - (void)setTabletAreaLeft:(float)l top:(float)t right:(float)r bottom:(float)b; 71 | - (void)setScreenAreaLeft:(float)l top:(float)t right:(float)r bottom:(float)b; 72 | - (void)setMappingForTip:(int)tip side1:(int)s1 side2:(int)s2 eraser:(int)e; 73 | - (void)setMouseMode:(BOOL)enabled andScaling:(float)s; 74 | 75 | - (void)addPresetNamed:(NSString*)n; 76 | 77 | - (void)setTabletConstraint:(NSSize)size; 78 | - (BOOL)tabletIsConstrained; 79 | - (TMPreset*)activePreset; 80 | 81 | // Actions 82 | - (IBAction)selectedPreset:(id)sender; 83 | - (IBAction)addPreset:(id)sender; 84 | - (IBAction)doAddPreset:(id)sender; 85 | - (IBAction)renamePreset:(id)sender; 86 | - (IBAction)doRenamePreset:(id)sender; 87 | - (IBAction)deletePreset:(id)sender; 88 | - (IBAction)doDeletePreset:(id)sender; 89 | - (IBAction)presetChanged:(id)sender; 90 | - (IBAction)toggleConstrain:(id)sender; 91 | - (IBAction)toggleMouseMode:(id)sender; 92 | - (IBAction)cancelSheet:(id)sender; 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /prefpane/TMPresetsController.m: -------------------------------------------------------------------------------- 1 | /** 2 | * TMPresetsController.m 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | * 7 | * This controller connects the Preset model to 8 | * the Mapping view and the main TMController. 9 | * 10 | * - If presets exist load them into a local array 11 | * 12 | * - When [geom] arrives, either select the corresponding preset 13 | * or create/update the Custom preset 14 | * 15 | * NOTE - [geom] only arrives if the daemon is already 16 | * running when the preference pane starts. 17 | * 18 | * - When a preset changes automatically save it 19 | * 20 | * - The custom preset can be renamed 21 | * 22 | * - The last preset can't be deleted. If you delete the last preset 23 | * it just gets renamed "Custom" 24 | */ 25 | 26 | #import "TMPreset.h" 27 | #import "TMPresetsController.h" 28 | #import "TMController.h" 29 | #import "TMAreaChooserScreen.h" 30 | #import "TMAreaChooserTablet.h" 31 | #import "../common/Constants.h" 32 | 33 | #import "TabletMagicPref.h" 34 | 35 | #define kCustom @"Custom" 36 | 37 | @implementation TMPresetsController 38 | 39 | // 40 | // init is called before the mainViewDidLoad of the controller 41 | // so here we create the basic presets items 42 | // 43 | - (id)init { 44 | if ((self = [super init])) { 45 | activePresetIndex = 0; 46 | activePreset = nil; 47 | presetsArray = nil; 48 | } 49 | 50 | return self; 51 | } 52 | 53 | - (void)mainViewDidLoad { 54 | [ self loadPresets ]; // if preferences save on init this must be in init above 55 | [ self initControls ]; // the view has to be loaded before this works 56 | [ self updatePresetsMenu ]; 57 | } 58 | 59 | - (BOOL)apply2b8Patches { 60 | BOOL didUpdates = YES; 61 | 62 | NSDictionary *prefs = [ [NSUserDefaults standardUserDefaults] persistentDomainForName:[[thePane bundle] bundleIdentifier] ]; 63 | if (prefs != nil) 64 | didUpdates = ([ prefs objectForKey:keyDidFixButtons ] != nil); 65 | 66 | if (!didUpdates) { 67 | int b; 68 | for (int i=(int)[presetsArray count]; i--;) { 69 | TMPreset *preset = [ [ TMPreset alloc ] initWithDictionary:[presetsArray objectAtIndex:i] ]; 70 | if ((b = [ preset buttonEraser ]) >= kSystemButton3) [ preset setButtonEraser:b+3 ]; 71 | if ((b = [ preset buttonTip ]) >= kSystemButton3) [ preset setButtonTip:b+3 ]; 72 | if ((b = [ preset buttonSwitch1 ]) >= kSystemButton3) [ preset setButtonSwitch1:b+3 ]; 73 | if ((b = [ preset buttonSwitch2 ]) >= kSystemButton3) [ preset setButtonSwitch2:b+3 ]; 74 | [ presetsArray replaceObjectAtIndex:i withObject:[preset dictionary] ]; 75 | } 76 | 77 | [ self activatePresetIndex:-1 ]; 78 | } 79 | 80 | return !didUpdates; 81 | } 82 | 83 | - (void)loadPresets { 84 | if (presetsArray == nil) 85 | presetsArray = [ [ NSMutableArray alloc ] initWithCapacity:10 ]; 86 | 87 | if (activePreset == nil) 88 | activePreset = [ [ TMPreset alloc ] init ]; 89 | 90 | activePresetIndex = 0; 91 | 92 | NSDictionary *prefs = [ [NSUserDefaults standardUserDefaults] persistentDomainForName:[[thePane bundle] bundleIdentifier] ]; 93 | 94 | if (prefs != nil) { 95 | #if !ARC_ENABLED 96 | [ prefs retain ]; 97 | #endif 98 | 99 | NSDictionary *dict = [ prefs objectForKey:keyPresets ]; 100 | if (dict) { 101 | NSArray *anArray = [dict objectForKey:keyPresetList]; 102 | 103 | if (anArray) { 104 | [ presetsArray setArray:[dict objectForKey:keyPresetList] ]; 105 | 106 | activePresetIndex = [ [dict objectForKey:keySelectedPreset] intValue ]; 107 | } 108 | } 109 | 110 | #if !ARC_ENABLED 111 | [ prefs release ]; 112 | #endif 113 | } 114 | 115 | if (!presetsArray || [presetsArray count] == 0) { 116 | [ presetsArray addObject:[activePreset dictionary] ]; 117 | } 118 | 119 | [ self activatePresetIndex:activePresetIndex ]; 120 | } 121 | 122 | - (void)activatePresetIndex:(int)i { 123 | if (i < (int)[ presetsArray count ]) { 124 | (void)[ activePreset initWithDictionary:[presetsArray objectAtIndex:(i < 0) ? activePresetIndex : i] ]; 125 | [ self updateControlsForActivePreset ]; 126 | } 127 | } 128 | 129 | - (void)sendPresetToDaemon { 130 | [ theController sendMessageToDaemon:[ activePreset daemonMessage ] ]; 131 | } 132 | 133 | - (void)sendMouseModeToDaemon { 134 | [ theController sendMessageToDaemon:[ activePreset mouseModeMessage ] ]; 135 | } 136 | 137 | - (void)updatePresetsMenu { 138 | int count = (int)[presetsArray count]; 139 | [ popupPresets removeAllItems ]; 140 | 141 | if (count) { 142 | int i, uid; 143 | for (i=0; i1) ]; 157 | [ buttonRename setEnabled:YES ]; 158 | } 159 | else { 160 | [ popupPresets setEnabled:NO ]; 161 | [ buttonDelete setEnabled:NO ]; 162 | [ buttonRename setEnabled:NO ]; 163 | } 164 | } 165 | 166 | - (void)activatePresetMatching:(char*)geom { 167 | int tl, tt, tr, tb, sl, st, sr, sb, b0, b1, b2, be, mm; 168 | float ms; 169 | 170 | int i, foundIndex = -1; 171 | 172 | TMPreset *p = [[TMPreset alloc] init]; 173 | 174 | if (14 == sscanf(geom, "%*s %u %d %d %d : %d %d %d %d : %d %d %d %d : %d %f", 175 | &tl, &tt, &tr, &tb, &sl, &st, &sr, &sb, &b0, &b1, &b2, &be, &mm, &ms)) { 176 | // Try to find a matching preset 177 | for (i=0;i<[presetsArray count];i++) { 178 | (void)[p initWithDictionary:[presetsArray objectAtIndex:i]]; 179 | 180 | if ( [p matchesTabletLeft:tl top:tt right:tr bottom:tb] 181 | && [p matchesScreenLeft:sl top:st right:sr bottom:sb] 182 | && [p matchesButtonTip:b0 switch1:b1 switch2:b2 eraser:be] 183 | && [p matchesMouseMode:mm scaling:ms]) { 184 | foundIndex = i; 185 | break; 186 | } 187 | } 188 | 189 | // If none was found, check for the name "Custom" 190 | if (foundIndex == -1) { 191 | for (i=0;i<[presetsArray count];i++) { 192 | if ( NSOrderedSame == [[[presetsArray objectAtIndex:i] objectForKey:@keyName] compare:[thePane localizedString:kCustom] options:NSCaseInsensitiveSearch] ) { 193 | foundIndex = i; 194 | break; 195 | } 196 | } 197 | } 198 | 199 | if (foundIndex == -1) { 200 | [ self addPresetNamed:[thePane localizedString:kCustom] ]; 201 | foundIndex = (int)[presetsArray count] - 1; 202 | } 203 | 204 | if (foundIndex != activePresetIndex) { 205 | [ popupPresets selectItemAtIndex:foundIndex ]; 206 | [ self activatePresetIndex:foundIndex ]; 207 | } 208 | } 209 | 210 | #if !ARC_ENABLED 211 | [ p release ]; 212 | #endif 213 | } 214 | 215 | - (void)updateControlsForActivePreset { 216 | TMPreset *p = activePreset; 217 | 218 | [ buttonConstrain setState:[p constrained] ]; 219 | [ self reflectConstrainSetting:[p constrained] ]; 220 | 221 | [ checkMouseMode setState:[p mouseMode] ]; 222 | [ sliderScaling setFloatValue:[p mouseScaling] ]; 223 | 224 | [ chooserScreen setFromPresetWidth:[p screenWidth] height:[p screenHeight] left:[p screenLeft] top:[p screenTop] right:[p screenRight] bottom:[p screenBottom] ]; 225 | [ chooserTablet setFromPresetWidth:[p tabletRangeX] height:[p tabletRangeY] left:[p tabletLeft] top:[p tabletTop] right:[p tabletRight] bottom:[p tabletBottom] ]; 226 | 227 | [ popupStylusTip selectItemWithTag:[p buttonTip] ]; 228 | [ popupSwitch1 selectItemWithTag:[p buttonSwitch1] ]; 229 | [ popupSwitch2 selectItemWithTag:[p buttonSwitch2] ]; 230 | [ popupEraser selectItemWithTag:[p buttonEraser] ]; 231 | } 232 | 233 | - (void)geometryReceived:(char*)geom { 234 | int tl, tt, tr, tb, sl, st, sr, sb, b0, b1, b2, be, mm; 235 | float ms; 236 | if (14 == sscanf(geom, "%*s %u %d %d %d : %d %d %d %d : %d %d %d %d : %d %f", 237 | &tl, &tt, &tr, &tb, &sl, &st, &sr, &sb, &b0, &b1, &b2, &be, &mm, &ms)) { 238 | [ self activatePresetMatching:geom ]; 239 | 240 | [ activePreset setConstrained:NO ]; 241 | 242 | if (tr > tl && tb > tt) 243 | [ self setTabletAreaLeft:tl top:tt right:tr bottom:tb ]; 244 | 245 | [ self setScreenWidth:[ chooserScreen maxWidth ] height:[ chooserScreen maxHeight ] ]; 246 | [ self setScreenAreaLeft:sl top:st right:sr bottom:sb ]; 247 | [ self setMappingForTip:b0 side1:b1 side2:b2 eraser:be ]; 248 | [ self setMouseMode:mm andScaling:ms ]; 249 | 250 | if (tr <= tl || tb <= tt) 251 | [ self sendPresetToDaemon ]; 252 | 253 | [ self synchronizePresetInArray ]; 254 | [ self updateControlsForActivePreset ]; 255 | } 256 | } 257 | 258 | - (void)initControls { 259 | //NSString *imagePath = [[thePane bundle] pathForImageResource:@"button.jpg" ]; 260 | //NSImage *img1 = [[NSImage alloc] initWithContentsOfFile:imagePath]; 261 | //NSImage *img2 = [ theController retainedHighlightedImageForImage:img1 ]; 262 | 263 | NSButtonCell *cell = [buttonConstrain cell]; 264 | //[cell setImage:img1]; 265 | //[cell setAlternateImage:img2]; 266 | [cell setShowsStateBy:NSChangeBackgroundCellMask]; 267 | [cell setHighlightsBy:NSPushInCellMask]; 268 | //[ buttonConstrain setTitle:[ thePane localizedString:@"< constrain <" ] ]; 269 | 270 | // 271 | // Set the initial dimensions for the Screen Chooser 272 | // 273 | [ chooserScreen calibrate:YES ]; 274 | 275 | // 276 | // At this point in the initialization the tablet 277 | // probably hasn't even been queried so use a sane 278 | // default. Soon we'll load the preset. Once a tablet 279 | // is found TMController will read its current 280 | // settings and update the w/h in the control for the 281 | // tablet's max coordinates. 282 | // (important to make sure the order remains the same) 283 | // 284 | [ chooserTablet setMaxWidth:k12inches1270ppi height:k12inches1270ppi ]; 285 | [ chooserTablet setAreaLeft:0 top:0 right:k12inches1270ppi-1 bottom:k12inches1270ppi-1 ]; 286 | 287 | // Update controls based on the preset 288 | [ self updateControlsForActivePreset ]; 289 | } 290 | 291 | 292 | /* 293 | When the screen changes recalculate the overall area 294 | and the current values will be set proportional to 295 | the original. 296 | */ 297 | - (void)screenChanged { 298 | // Recalibrate the Screen Chooser (but don't reset) 299 | [ chooserScreen calibrate:NO ]; 300 | } 301 | 302 | /* 303 | For one reason or another the tablet scale can 304 | change intermittently. 305 | */ 306 | - (void)updateTabletScaleX:(unsigned)x y:(unsigned)y { 307 | [ chooserTablet updateMaxWidth:x height:y ]; 308 | } 309 | 310 | 311 | #pragma mark - 312 | 313 | - (void)setTabletRangeX:(unsigned)x y:(unsigned)y { 314 | [ activePreset setTabletRangeX:x y:y ]; 315 | } 316 | 317 | - (void)setScreenWidth:(unsigned)w height:(unsigned)h { 318 | [ activePreset setScreenWidth:w height:h ]; 319 | } 320 | 321 | - (void)setTabletAreaLeft:(float)l top:(float)t right:(float)r bottom:(float)b { 322 | [ activePreset setTabletAreaLeft:l top:t right:r bottom:b ]; 323 | } 324 | 325 | - (void)setScreenAreaLeft:(float)l top:(float)t right:(float)r bottom:(float)b { 326 | [ activePreset setScreenAreaLeft:l top:t right:r bottom:b ]; 327 | } 328 | 329 | - (void)setMappingForTip:(int)tip side1:(int)s1 side2:(int)s2 eraser:(int)e { 330 | [ activePreset setMappingForTip:tip side1:s1 side2:s2 eraser:e ]; 331 | } 332 | 333 | - (void)setMouseMode:(BOOL)enabled andScaling:(float)s { 334 | [ activePreset setMouseMode:enabled ]; 335 | [ activePreset setMouseScaling:s ]; 336 | } 337 | 338 | - (void)setTabletConstraint:(NSSize)size { 339 | [ chooserTablet constrain:size ]; 340 | } 341 | 342 | - (void)updatePresetFromControls { 343 | [ activePreset setScreenWidth:[chooserScreen maxWidth] height:[chooserScreen maxHeight] ]; 344 | [ activePreset setTabletRangeX:[chooserTablet maxWidth] y:[chooserTablet maxHeight] ]; 345 | [ activePreset setScreenAreaLeft:[chooserScreen left] top:[chooserScreen top] right:[chooserScreen right] bottom:[chooserScreen bottom] ]; 346 | [ activePreset setTabletAreaLeft:[chooserTablet left] top:[chooserTablet top] right:[chooserTablet right] bottom:[chooserTablet bottom] ]; 347 | [ activePreset setMappingForTip:(int)[[popupStylusTip selectedItem] tag] 348 | side1:(int)[[popupSwitch1 selectedItem] tag] 349 | side2:(int)[[popupSwitch2 selectedItem] tag] 350 | eraser:(int)[[popupEraser selectedItem] tag] ]; 351 | 352 | [ activePreset setMouseMode:[checkMouseMode state]==NSOnState ]; 353 | [ activePreset setMouseScaling:[sliderScaling floatValue] ]; 354 | [ activePreset setConstrained:[buttonConstrain state]==NSOnState ]; 355 | 356 | [ self synchronizePresetInArray ]; 357 | [ theController updateAutoStartSoon ]; 358 | } 359 | 360 | - (void)reflectConstrainSetting:(BOOL)b { 361 | if (b) 362 | [ chooserTablet constrain:[ chooserScreen activeArea ] ]; 363 | else 364 | [ chooserTablet disableConstrain ]; 365 | } 366 | 367 | - (void)synchronizePresetInArray { 368 | [ presetsArray replaceObjectAtIndex:activePresetIndex withObject:[activePreset dictionary] ]; 369 | } 370 | 371 | #pragma mark - Actions 372 | 373 | - (IBAction)selectedPreset:(id)sender { 374 | activePresetIndex = (int)[sender indexOfSelectedItem]; 375 | [ self activatePresetIndex:activePresetIndex ]; 376 | [ self sendPresetToDaemon ]; 377 | } 378 | 379 | - (IBAction)addPreset:(id)sender { 380 | [ editAdd setStringValue:[ thePane localizedString:@"Untitled Preset" ] ]; 381 | [ editAdd selectText:self ]; 382 | 383 | [ NSApp beginSheet:sheetAdd 384 | modalForWindow:[[thePane mainView] window] 385 | modalDelegate:self 386 | didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) 387 | contextInfo:nil 388 | ]; 389 | } 390 | 391 | - (IBAction)deletePreset:(id)sender { 392 | [ textDelete setStringValue: 393 | [ NSString stringWithFormat: 394 | [ thePane localizedString:@"Are you sure you want to delete the preset \"%@\" ?" ], 395 | [activePreset name] 396 | ] 397 | ]; 398 | 399 | [ NSApp beginSheet:sheetDelete 400 | modalForWindow:[[thePane mainView] window] 401 | modalDelegate:self 402 | didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) 403 | contextInfo:nil 404 | ]; 405 | } 406 | 407 | - (IBAction)renamePreset:(id)sender { 408 | [ editRename setStringValue:[activePreset name] ]; 409 | [ editRename selectText:self ]; 410 | 411 | [ NSApp beginSheet:sheetRename 412 | modalForWindow:[[thePane mainView] window] 413 | modalDelegate:self 414 | didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) 415 | contextInfo:nil 416 | ]; 417 | } 418 | 419 | - (IBAction)cancelSheet:(id)sender { 420 | [ NSApp endSheet:[ sender window ] ]; 421 | } 422 | 423 | - (IBAction)doAddPreset:(id)sender { 424 | if (![[editAdd stringValue] isEqualToString:@""]) { 425 | [ NSApp endSheet:[ sender window ] ]; 426 | [ self addPresetNamed:[editAdd stringValue] ]; 427 | } 428 | } 429 | 430 | -(void)addPresetNamed:(NSString*)n { 431 | TMPreset *newPreset = [[TMPreset alloc] init]; 432 | (void)[ newPreset initWithDictionary:[activePreset dictionary] ]; 433 | [ newPreset setName:n ]; 434 | [ presetsArray addObject:[newPreset dictionary] ]; 435 | #if !ARC_ENABLED 436 | [ newPreset release ]; 437 | #endif 438 | activePresetIndex = (int)[ presetsArray count ] - 1; 439 | (void)[ activePreset initWithDictionary:[presetsArray objectAtIndex:activePresetIndex] ]; 440 | [ self updatePresetsMenu ]; 441 | } 442 | 443 | - (IBAction)doDeletePreset:(id)sender { 444 | [ NSApp endSheet:[ sender window ] ]; 445 | 446 | [ presetsArray removeObjectAtIndex:activePresetIndex ]; 447 | 448 | if (activePresetIndex > 0 && activePresetIndex >= [ presetsArray count ]) 449 | activePresetIndex--; 450 | 451 | [ self updatePresetsMenu ]; 452 | [ self activatePresetIndex:activePresetIndex ]; 453 | [ self sendPresetToDaemon ]; 454 | } 455 | 456 | - (IBAction)doRenamePreset:(id)sender { 457 | if (![[editRename stringValue] isEqualToString:@""]) { 458 | [ NSApp endSheet:[ sender window ] ]; 459 | [ activePreset setName:[editRename stringValue] ]; 460 | [ presetsArray replaceObjectAtIndex:activePresetIndex withObject:[activePreset dictionary] ]; 461 | [ self updatePresetsMenu ]; 462 | } 463 | } 464 | 465 | - (void)didEndSheet:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo { 466 | [ sheet orderOut:self ]; 467 | } 468 | 469 | - (IBAction)presetChanged:(id)sender { 470 | [ self updatePresetFromControls ]; 471 | 472 | if ([ theController isDaemonLoaded:NO ]) 473 | [ self sendPresetToDaemon ]; 474 | } 475 | 476 | - (IBAction)toggleConstrain:(id)sender { 477 | [ self reflectConstrainSetting:[buttonConstrain state]==NSOnState ]; 478 | [ self updatePresetFromControls ]; 479 | } 480 | 481 | - (IBAction)toggleMouseMode:(id)sender { 482 | [ activePreset setMouseMode:[sender state]==NSOnState ]; 483 | [ self sendMouseModeToDaemon ]; 484 | [ self synchronizePresetInArray ]; 485 | [ theController updateAutoStartSoon ]; 486 | } 487 | 488 | - (IBAction)mouseScalingChanged:(id)sender { 489 | [ activePreset setMouseScaling:[sender floatValue] ]; 490 | [ self sendMouseModeToDaemon ]; 491 | [ self synchronizePresetInArray ]; 492 | [ theController updateAutoStartSoon ]; 493 | } 494 | 495 | #pragma mark - 496 | 497 | - (TMPreset*)activePreset { 498 | return activePreset; 499 | } 500 | 501 | - (NSDictionary*)dictionary { 502 | static NSDictionary *dict = NULL; 503 | 504 | if (dict) { 505 | #if !ARC_ENABLED 506 | [ dict release ]; 507 | #else 508 | dict = nil; 509 | #endif 510 | } 511 | 512 | NSArray *keys = [NSArray arrayWithObjects:keyPresetList, keySelectedPreset, nil]; 513 | NSArray *values = [NSArray arrayWithObjects:presetsArray, NSINT(activePresetIndex), nil]; 514 | dict = [[NSDictionary alloc] initWithObjects:values forKeys:keys]; 515 | 516 | return dict; 517 | } 518 | 519 | - (BOOL)tabletIsConstrained { return [ chooserTablet isConstrained ]; } 520 | 521 | @end 522 | -------------------------------------------------------------------------------- /prefpane/TMScratchpad.h: -------------------------------------------------------------------------------- 1 | /** 2 | * TMScratchpad.h 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | @interface TMScratchpad : NSView { 9 | BOOL smoothing; 10 | NSPoint startPoint; 11 | float startPressure; 12 | IBOutlet NSColorWell *penColor; 13 | IBOutlet NSColorWell *eraserColor; 14 | IBOutlet NSSlider *penFlow; 15 | IBOutlet NSSlider *eraserFlow; 16 | } 17 | 18 | - (IBAction)clear:(id)sender; 19 | - (IBAction)toggleSmoothing:(id)sender; 20 | 21 | - (void)handleProximity:(NSNotification *)proxNotice; 22 | - (void)drawBlobAtPoint:(NSPoint)point withPressure:(float)pressure erasing:(BOOL)is_eraser; 23 | 24 | - (void)_tabletProximity:(NSEvent *)theEvent; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /prefpane/TMScratchpad.m: -------------------------------------------------------------------------------- 1 | /** 2 | * TMScratchpad.m 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | #import "TMScratchpad.h" 9 | #import "../common/Constants.h" 10 | 11 | @implementation TMScratchpad 12 | 13 | - (id)initWithFrame:(NSRect)frameRect { 14 | if ((self = [super initWithFrame:frameRect]) != nil) { 15 | // Add initialization code here 16 | smoothing = YES; 17 | 18 | // Requires 10.6 or later... 19 | [NSEvent addLocalMonitorForEventsMatchingMask: NSTabletProximityMask 20 | handler: ^(NSEvent* theEvent) { 21 | [self _tabletProximity: theEvent]; 22 | return theEvent; 23 | } 24 | ]; 25 | 26 | [NSEvent addGlobalMonitorForEventsMatchingMask: NSTabletProximityMask 27 | handler: ^(NSEvent* theEvent) { 28 | [self _tabletProximity: theEvent]; 29 | } 30 | ]; 31 | 32 | 33 | } 34 | return self; 35 | } 36 | 37 | - (void)awakeFromNib { 38 | // Must inform the window that we want mouse moves after all object 39 | // are created and linked. 40 | // Let our internal routine make the API call so that everything 41 | // stays in sych. Change the value in the init routine to change 42 | // the default behavior 43 | // Mouse moves must be captured if you want to recieve Proximity Events 44 | /* 45 | [[self window] setAcceptsMouseMovedEvents:YES]; 46 | 47 | //Must register to be notified when device come in and out of Prox 48 | [[NSNotificationCenter defaultCenter] addObserver:self 49 | selector:@selector(handleProximity:) 50 | name:kProximityNotification 51 | object:nil]; 52 | */ 53 | } 54 | 55 | // 56 | // The proximity notification is based on the Proximity Event. 57 | // (see CarbonEvents.h). The proximity notification will give you detailed 58 | // information about the device that was either just placed on, or just 59 | // taken off of the tablet. 60 | // 61 | // In this sample code, the Proximity notification is used to determine if 62 | // the pen TIP or ERASER is being used. This information is not provided in 63 | // the embedded tablet event. 64 | // 65 | // Also, on the Intuos line of tablets, each transducer has a unique ID, 66 | // even when different transducers are of the same type. We get that 67 | // information here so we can keep track of the Color assigned to each 68 | // transducer. 69 | // 70 | - (void) handleProximity:(NSNotification *)proxNotice { 71 | /* 72 | NSDictionary *proxDict = [proxNotice userInfo]; 73 | UInt8 enterProximity; 74 | UInt8 pointerType; 75 | UInt16 deviceID; 76 | 77 | [[proxDict objectForKey:kEnterProximity] getValue:&enterProximity]; 78 | 79 | if (enterProximity != 0) { //Enter Proximity 80 | [[proxDict objectForKey:kPointerType] getValue:&pointerType]; 81 | erasing = (pointerType == NX_TABLET_POINTER_ERASER); 82 | 83 | [[proxDict objectForKey:kDeviceID] getValue:&deviceID]; 84 | 85 | if ([knownDevices setCurrentDeviceByID: deviceID] == NO) { 86 | //must be a new device 87 | Transducer *newDevice = [[Transducer alloc] 88 | initWithIdent: deviceID 89 | color: [NSColor blackColor]]; 90 | 91 | [knownDevices addDevice:newDevice]; 92 | #if !ARC_ENABLED 93 | [newDevice release]; 94 | #endif 95 | [knownDevices setCurrentDeviceByID: deviceID]; 96 | } 97 | 98 | [[NSNotificationCenter defaultCenter] 99 | postNotificationName:WTViewUpdatedNotification 100 | object: self]; 101 | } 102 | */ 103 | } 104 | 105 | - (void)drawRect:(NSRect)rect { 106 | [[eraserColor color] setFill]; 107 | NSRectFill(rect); 108 | 109 | [[NSColor blackColor] setFill]; 110 | NSFrameRectWithWidth(rect, 1.0f); 111 | } 112 | 113 | BOOL tablet_eraser = NO; 114 | 115 | - (void)_tabletProximity:(NSEvent *)theEvent { 116 | NSPointingDeviceType device_type = [theEvent pointingDeviceType]; 117 | tablet_eraser = device_type == NSEraserPointingDevice; 118 | } 119 | 120 | - (void)mouseDown:(NSEvent *)theEvent { 121 | if ([theEvent subtype] == NSTabletPointEventSubtype) { 122 | 123 | startPoint = [ self convertPoint:[theEvent locationInWindow] fromView:nil ]; 124 | startPressure = [theEvent pressure]; 125 | 126 | [self drawBlobAtPoint:startPoint withPressure:[theEvent pressure] erasing:tablet_eraser]; 127 | } 128 | } 129 | 130 | - (void)mouseDragged:(NSEvent *)theEvent { 131 | if ([theEvent subtype] == NSTabletPointEventSubtype) { 132 | 133 | NSPoint newPoint = [ self convertPoint:[theEvent locationInWindow] fromView:nil ]; 134 | float newPressure = [theEvent pressure]; 135 | if (smoothing) { 136 | float dx = newPoint.x - startPoint.x, 137 | dy = newPoint.y - startPoint.y, 138 | dist = sqrt(dx*dx+dy*dy), 139 | fx = dx / dist, fy = dy / dist; 140 | int distint = floorf(dist); 141 | float r = newPressure * [(tablet_eraser ? eraserFlow : penFlow) floatValue ]; 142 | if (distint > 1 && distint >= r) { 143 | NSPoint point = startPoint; 144 | float press = startPressure, pstep = (newPressure - startPressure) / (float)distint; 145 | // the original point was already drawn (mouseDown) so... 146 | // draw from the 2nd to the next-to-last 147 | for (int i=distint - 1; i--;) { 148 | point.x += fx; 149 | point.y += fy; 150 | press += pstep; 151 | [ self drawBlobAtPoint:point withPressure:press erasing:tablet_eraser ]; 152 | } 153 | 154 | // NSAffineTransform *transform = [NSAffineTransform transform]; 155 | // [transform translateXBy: 10.0 yBy: 10.0]; 156 | // [bezierPath transformUsingAffineTransform: transform]; 157 | } 158 | } 159 | 160 | [ self drawBlobAtPoint:newPoint withPressure:newPressure erasing:tablet_eraser ]; 161 | startPoint = newPoint; 162 | startPressure = newPressure; 163 | } 164 | } 165 | 166 | - (void)mouseUp:(NSEvent *)theEvent { 167 | // tablet_eraser = NO; 168 | } 169 | 170 | - (void)drawBlobAtPoint:(NSPoint)point withPressure:(float)pressure erasing:(BOOL)is_eraser { 171 | [ self lockFocus ]; 172 | [ NSBezierPath clipRect:NSInsetRect([self bounds], 1.0, 1.0) ]; 173 | 174 | [[(is_eraser ? eraserColor : penColor) color] setFill]; 175 | float r = pressure * [(is_eraser ? eraserFlow : penFlow) floatValue ]; 176 | NSBezierPath *bez = [ NSBezierPath bezierPathWithOvalInRect:NSMakeRect(point.x-r, point.y-r, r*2.0f, r*2.0f) ]; 177 | [ bez fill ]; 178 | 179 | [ self unlockFocus ]; 180 | } 181 | 182 | - (IBAction)clear:(id)sender { 183 | [ self setNeedsDisplay:YES ]; 184 | } 185 | 186 | - (IBAction)toggleSmoothing:(id)sender { 187 | smoothing = ([sender state] == NSOnState); 188 | } 189 | 190 | @end 191 | -------------------------------------------------------------------------------- /prefpane/TabletMagicPref.h: -------------------------------------------------------------------------------- 1 | /** 2 | * TabletMagicPref.h 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | #import 9 | 10 | typedef struct { 11 | NSInteger majorVersion; 12 | NSInteger minorVersion; 13 | NSInteger patchVersion; 14 | } TMOperatingSystemVersion; 15 | 16 | @interface TabletMagicPref : NSPreferencePane { 17 | TMOperatingSystemVersion systemVersion; 18 | BOOL has_tablet_events; 19 | } 20 | 21 | // 22 | // mainViewDidLoad 23 | // awakeFromNIB for Preference Panes - called when the pane is ready 24 | // 25 | - (void) mainViewDidLoad; 26 | - (void) willUnselect; 27 | 28 | // 29 | // paneTerminating 30 | // Receives a notification when the pane is quit 31 | // 32 | - (void) paneTerminating:(NSNotification*)aNotification; 33 | 34 | // 35 | // screenChanged 36 | // Receives a notification whenever the screen configuration changes 37 | // 38 | - (void) screenChanged:(NSNotification*)aNotification; 39 | 40 | - (TMOperatingSystemVersion*) systemVersion; 41 | - (BOOL) systemVersionAtLeastMajor:(long)maj minor:(long)min; 42 | - (BOOL) systemVersionBeforeMajor:(long)maj minor:(long)min; 43 | - (BOOL) canUseTabletEvents; 44 | - (NSBundle*) bundle; 45 | - (NSString*) localizedString:(NSString*)string; 46 | 47 | @end 48 | 49 | extern TabletMagicPref *thePane; 50 | -------------------------------------------------------------------------------- /prefpane/TabletMagicPref.m: -------------------------------------------------------------------------------- 1 | /** 2 | * TabletMagicPref.m 3 | * 4 | * TabletMagicPrefPane 5 | * Thinkyhead Software 6 | */ 7 | 8 | #import "TabletMagicPref.h" 9 | #import "TMController.h" 10 | 11 | TabletMagicPref *thePane; 12 | 13 | @implementation TabletMagicPref 14 | 15 | - (void) mainViewDidLoad { 16 | thePane = self; 17 | 18 | #if __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8 19 | // This replacement is available from 10.8 onward 20 | NSOperatingSystemVersion ver = [[NSProcessInfo processInfo] operatingSystemVersion]; 21 | systemVersion.majorVersion = ver.majorVersion; 22 | systemVersion.minorVersion = ver.minorVersion; 23 | systemVersion.patchVersion = ver.patchVersion; 24 | #else 25 | // This method may be available in 10.9 26 | // or by extending NSProcessInfo with a category 27 | if ([NSProcessInfo respondsToSelector:@selector(operatingSystemVersion)]) { 28 | NSOperatingSystemVersion ver = [[NSProcessInfo processInfo] operatingSystemVersion]; 29 | systemVersion.majorVersion = ver.majorVersion; 30 | systemVersion.minorVersion = ver.minorVersion; 31 | systemVersion.patchVersion = ver.patchVersion; 32 | } 33 | else { 34 | // Deprecated since 10.8 35 | SInt32 val; 36 | Gestalt(gestaltSystemVersionMajor, &val); systemVersion.majorVersion = val; 37 | Gestalt(gestaltSystemVersionMinor, &val); systemVersion.minorVersion = val; 38 | Gestalt(gestaltSystemVersionBugFix, &val); systemVersion.patchVersion = val; 39 | } 40 | #endif 41 | 42 | has_tablet_events = [ self systemVersionAtLeastMajor:10 minor:3 ]; 43 | 44 | // Notify us if the preference pane is closed 45 | [[NSNotificationCenter defaultCenter] addObserver:self 46 | selector:@selector(paneTerminating) 47 | name:NSApplicationWillTerminateNotification 48 | object:nil]; 49 | 50 | [[NSNotificationCenter defaultCenter] addObserver:self 51 | selector:@selector(screenChanged) 52 | name:NSApplicationDidChangeScreenParametersNotification 53 | object:nil]; 54 | 55 | [ theController mainViewDidLoad ]; 56 | } 57 | 58 | - (void) willUnselect { 59 | [ theController paneWillUnselect ]; 60 | } 61 | 62 | - (void) didSelect { 63 | [ theController paneDidSelect ]; 64 | } 65 | 66 | - (void) paneTerminating:(NSNotification*)aNotification { 67 | [ theController paneTerminating ]; 68 | } 69 | 70 | - (void) screenChanged:(NSNotification*)aNotification { 71 | [ theController screenChanged ]; 72 | } 73 | 74 | - (TMOperatingSystemVersion*) systemVersion { 75 | return &systemVersion; 76 | } 77 | 78 | - (BOOL) systemVersionAtLeastMajor:(long)maj minor:(long)min { 79 | return systemVersion.majorVersion >= maj || (systemVersion.majorVersion == maj && systemVersion.minorVersion >= min); 80 | } 81 | 82 | - (BOOL) systemVersionBeforeMajor:(long)maj minor:(long)min { 83 | return systemVersion.majorVersion < maj || (systemVersion.majorVersion == maj && systemVersion.minorVersion < min); 84 | } 85 | 86 | - (BOOL) canUseTabletEvents { 87 | return has_tablet_events; 88 | } 89 | 90 | - (NSBundle*) bundle { 91 | return [NSBundle bundleForClass:[self class]]; 92 | } 93 | 94 | - (NSString*) localizedString:(NSString*)string { 95 | return NSLocalizedStringFromTableInBundle(string, nil, [self bundle], @"Convenience method"); 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /prefpane/TabletMagic_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'TabletMagic' target in the 'TabletMagic' project. 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #define ARC_ENABLED (__has_feature(objc_arc) && __clang_major__ >= 3) 9 | #endif 10 | 11 | -------------------------------------------------------------------------------- /prefpane/fr.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | CFBundleName = "TabletMagic"; 4 | CFBundleShortVersionString = "2.0.0"; 5 | CFBundleGetInfoString = "TabletMagic Version 2.0.0, Copyright (c) 2022 Thinkyhead Software"; 6 | NSHumanReadableCopyright = "Copyright (c) 2022 Thinkyhead Software"; 7 | 8 | -------------------------------------------------------------------------------- /prefpane/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Kill Sheet */ 2 | "Kill TabletMagicDaemon?" = "Voulez-vous tuer le démon ?"; 3 | "This will kill the TabletMagicDaemon process. Click the Enabled checkbox to start it up again." = "Ceci arrêtera l'opération TabletMagicDaemon. Cliquez la case \"activé\" pour le relancer."; 4 | "Kill It!" = "Tuer le !"; 5 | "Cancel" = "Annuler"; 6 | 7 | /* Port and Tablet */ 8 | "Automatic" = "Automatique"; 9 | "Daemon Not Running" = "Deamon ne fonctionne pas"; 10 | "Starting Daemon..." = "Le daemon démarre..."; 11 | "Looking for a tablet..." = "Rechercher une tablette..."; 12 | "SD Fallback" = "SD en dernier recours"; 13 | "No Tablet Found" = "Aucune tablette"; 14 | "Unknown" = "Tablette inconnu"; 15 | 16 | /* Mapping Pane */ 17 | "Untitled Preset" = "Sans titre"; 18 | "Custom" = "Personnalisée"; 19 | "Version %@" = "Version %@"; 20 | "max" = "max"; 21 | "all" = "tous"; 22 | "< constrain <" = "< contraindre"; 23 | "Are you sure you want to delete the preset \"%@\" ?" = "Êtes-vous certain de vouloir supprimer \"%@\" ?"; 24 | 25 | /* Testing Pane */ 26 | "Datastream (%@ %@)" = "Flux de données (%@ %@)"; 27 | "Binary" = "Binaire"; 28 | "ASCII" = "ASCII"; 29 | 30 | /* TabletPC Sheets */ 31 | "Enable TabletPC Digitizer?" = "Permettez Le Convertisseur de TabletPC ?"; 32 | "This will modify a core system component to enable your digitizer, if possible." = "Ceci modifiera un composant de système de noyau pour permettre votre tablette, si possible."; 33 | "Modify and Reboot" = "Modifiez et relancez"; 34 | "No Digitizer Found!" = "Convertisseur non trouvé !"; 35 | "Sorry, but the enabler couldn't find a digitizer in the I/O Registry." = "Désolé, mais l'enabler n'a pas pu trouver un convertisseur dans l'enregistrement d'I/O."; 36 | "Sorry, but the enabler failed to execute." = "Désolé, mais l'enabler n'a pas commencé."; 37 | "Okay" = "Ok"; 38 | 39 | /* Commands Menu */ 40 | "Do Self-Test" = "Faire l'autotest"; 41 | "Get Model & ROM Version" = "Modèle et version"; 42 | "Get Maximum Coordinates" = "Coordonnées maximum"; 43 | "Get Current Settings" = "Configuration actuelle"; 44 | "Get Setting M1" = "Configuration M1"; 45 | "Get Setting M2" = "Configuration M2"; 46 | "Start" = "Démarrage"; 47 | "Stop" = "Arrêter"; 48 | "Get Tablet Info" = "Information de Tablette"; 49 | "Sample at 133pps" = "Transmettre à 133p/s"; 50 | "Sample at 80pps" = "Transmettre à 80p/s"; 51 | "Sample at 40pps" = "Transmettre à 40p/s"; 52 | "Reset to Bit Pad Two" = "Réinitialiser à Bitpad 2"; 53 | "Reset to MM1201" = "Réinitialiser à MM1201"; 54 | "Reset to WACOM II-S" = "Réinitialiser à WACOM II-S"; 55 | "Reset to WACOM IV" = "Réinitialiser à WACOM IV"; 56 | "Reset to Defaults of Mode" = "Réinitialiser au défaut du mode"; 57 | "Enable Tilt Mode" = "Activer l'inclinaison"; 58 | "Disable Tilt Mode" = "Arrêter l'inclinaison"; 59 | "Suppressed Mode (IN2)" = "Mode Suppression (IN2)"; 60 | "Point Mode" = "Mode Point"; 61 | "Switch Stream Mode" = "Mode Touche-Flux"; 62 | "Stream Mode" = "Mode Flux"; 63 | "Continuous Data Mode" = "Mode continu"; 64 | "Trailing Data Mode" = "Mode Remorquage"; 65 | "Normal Data Mode" = "Mode normal"; 66 | "Origin UL" = "Origine GS"; 67 | "Origin LL" = "Origine GI"; 68 | "Scale 15240 x 15240" = "Échelle 15240 x 15240"; 69 | "Scale 32768 x 32768" = "Échelle 32768 x 32768"; 70 | "Enable Pressure Mode" = "Mode de pression"; 71 | "Disable Pressure Mode" = "Mode sans pression"; 72 | "ASCII Data Mode" = "Mode données ASCII"; 73 | "Binary Data Mode" = "Mode données Binaires"; 74 | "Enable Relative Mode" = "Mode Relatif"; 75 | "Disable Relative Mode" = "Mode Absolu"; 76 | "Set 1000p/i Resolution" = "Résolution 1000p/p"; 77 | "Set 50p/mm Resolution" = "Résolution 50p/mm"; 78 | "Enable All Menu Buttons" = "Tous les boutons de menu"; 79 | "Disable Setup Button" = "Désactiver le bouton \"Setup\""; 80 | "Disable Function Buttons" = "Désactiver les boutons de fonctions"; 81 | "Disable Pressure Buttons" = "Désactiver les boutons de pression"; 82 | "Pressure Buttons as Macros" = "Boutons de pression comme Macros"; 83 | "BA Command" = "Commande BA"; 84 | "LA Command" = "Commande LA"; 85 | "CA Command" = "Commande CA"; 86 | "OR Command" = "Commande OR"; 87 | "RC Command" = "Commande RC"; 88 | "RS Command" = "Commande RS"; 89 | "SB Command" = "Commande SB"; 90 | "YR Command" = "Commande YR"; 91 | "AS Command" = "Commande AS"; 92 | "DE Command" = "Commande DE"; 93 | "IC Command" = "Commande IC"; 94 | "PH Command" = "Commande PH"; 95 | "SC Command" = "Commande SC"; 96 | 97 | 98 | /* Tablet Events */ 99 | "Pen Engaged" = "Le stylet est près"; 100 | "Pen Disengaged" = "Le stylet est enlevé"; 101 | "Pen Down" = "Le stylet touche"; 102 | "Pen Up" = "Le stylet ne touche pas"; 103 | "Eraser Engaged" = "La gomme est près"; 104 | "Eraser Disengaged" = "La gomme est enlevée"; 105 | "Eraser Down" = "La gomme touche"; 106 | "Eraser Up" = "La gomme ne touche pas"; 107 | "Button Click" = "Clic de bouton"; 108 | "Button Release" = "Clic terminé"; 109 | -------------------------------------------------------------------------------- /prefpane/fr.lproj/TabletMagicSearchGroups.searchTerms: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tabletmagicMain 6 | 7 | localizableStrings 8 | 9 | 10 | index 11 | wacom, tablet, digitizer, serial, ink 12 | title 13 | TabletMagic 14 | 15 | 16 | 17 | tabletmagicSetupTab 18 | 19 | localizableStrings 20 | 21 | 22 | index 23 | wacom, tablet, setup, serial, origin, pressure, tilt, drawing, ink 24 | title 25 | TabletMagic Setup 26 | 27 | 28 | 29 | tabletmagicMappingTab 30 | 31 | localizableStrings 32 | 33 | 34 | index 35 | mapping, geometry, screen, buttons 36 | title 37 | TabletMagic Mapping 38 | 39 | 40 | 41 | tabletmagicTestingTab 42 | 43 | localizableStrings 44 | 45 | 46 | index 47 | test, try, monitor, log, logging, commands 48 | title 49 | TabletMagic Testing 50 | 51 | 52 | 53 | tabletmagicExtrasTab 54 | 55 | localizableStrings 56 | 57 | 58 | index 59 | ink, daemon, tabletmagicdaemon, kill, reset 60 | title 61 | TabletMagic Extras 62 | 63 | 64 | 65 | tabletmagicDonateTab 66 | 67 | localizableStrings 68 | 69 | 70 | index 71 | donate, github, oss, gpl 72 | title 73 | TabletMagic Donation 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /prefpane/include/GetPID.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkyhead/TabletMagic/3a067906765c82e063e61dede24fc0104fc79453/prefpane/include/GetPID.c -------------------------------------------------------------------------------- /prefpane/include/GetPID.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkyhead/TabletMagic/3a067906765c82e063e61dede24fc0104fc79453/prefpane/include/GetPID.h -------------------------------------------------------------------------------- /prefpane/it.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | CFBundleName = "TabletMagic"; 4 | CFBundleShortVersionString = "2.0.0"; 5 | CFBundleGetInfoString = "TabletMagic Versione 2.0.0, Copyright (c) 2022 Thinkyhead Software"; 6 | NSHumanReadableCopyright = "Copyright (c) 2022 Thinkyhead Software"; 7 | 8 | -------------------------------------------------------------------------------- /prefpane/it.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Kill Sheet */ 2 | "Kill TabletMagicDaemon?" = "Sicuri voler fermare TabletMagicDaemon?"; 3 | "This will kill the TabletMagicDaemon process. Click the Enabled checkbox to start it up again." = "Questo ucciderà il processo di TabletMagicDaemon. Per attivarlo di nuovo, selezionare la casella Attivo."; 4 | "Kill It!" = "Uccidilo!"; 5 | "Cancel" = "Annulla"; 6 | 7 | /* Port and Tablet */ 8 | "Automatic" = "Automatico"; 9 | "Daemon Not Running" = "Gestore spento"; 10 | "Starting Daemon..." = "Gestore sta partento..."; 11 | "Looking for a tablet..." = "Sto cercando la tavoletta..."; 12 | "SD Fallback" = "SD Fallback"; 13 | "No Tablet Found" = "Nessuna tavoletta trovata"; 14 | "Unknown" = "Sconosciuto"; 15 | 16 | /* Mapping Pane */ 17 | "Untitled Preset" = "Senza titolo"; 18 | "Custom" = "Personalizzata"; 19 | "Version %@" = "Versione %@"; 20 | "max" = "max"; 21 | "all" = "tutti"; 22 | "< constrain <" = "< vincola <"; 23 | "Are you sure you want to delete the preset \"%@\" ?" = "Sei sicuro di voler eliminare la impostazione \"%@\" ?"; 24 | 25 | /* Testing Pane */ 26 | "Datastream (%@ %@)" = "Dati della tavoletta (%@ %@)"; 27 | "Binary" = "Binario"; 28 | "ASCII" = "ASCII"; 29 | 30 | /* TabletPC Sheets */ 31 | "Enable TabletPC Digitizer?" = "Permetta Il Convertitore Di TabletPC?"; 32 | "This will modify a core system component to enable your digitizer, if possible." = "Ciò modificherà un componente di sistema di nucleo per permettere il vostro tavoletta, se possibile."; 33 | "Modify and Reboot" = "Modifichi e Ricominci"; 34 | "No Digitizer Found!" = "Nessun tavoletta è stato trovato!"; 35 | "Sorry, but the enabler couldn't find a digitizer in the I/O Registry." = "Spiacente, ma il enabler non ha potuto trovare un tavoletta nella registrazione di I/O."; 36 | "Sorry, but the enabler failed to execute." = "Spiacente, ma il enabler non è riuscito ad eseguire."; 37 | "Okay" = "Okay"; 38 | 39 | /* Commands Menu */ 40 | "Do Self-Test" = "Fai Self-test"; 41 | "Get Model & ROM Version" = "Ottieni Modello e Versione"; 42 | "Get Maximum Coordinates" = "Ottieni Limiti delle coordinate"; 43 | "Get Current Settings" = "Ottieni regolazioni correnti"; 44 | "Get Setting M1" = "Ottieni regolazioni M1"; 45 | "Get Setting M2" = "Ottieni regolazioni M2"; 46 | "Start" = "Avvia"; 47 | "Stop" = "Ferma"; 48 | "Get Tablet Info" = "Ottieni informazioni"; 49 | "Sample at 133pps" = "Campiona a 133p/s"; 50 | "Sample at 80pps" = "Campiona a 80p/s"; 51 | "Sample at 40pps" = "Campiona a 40p/s"; 52 | "Reset to Bit Pad Two" = "Reset a Bit Pad Two"; 53 | "Reset to MM1201" = "Reset a MM1201"; 54 | "Reset to WACOM II-S" = "Reset a WACOM II-S"; 55 | "Reset to WACOM IV" = "Reset a WACOM IV"; 56 | "Reset to Defaults of Mode" = "Reset a Default del Modo"; 57 | "Enable Tilt Mode" = "Attiva inclinazione"; 58 | "Disable Tilt Mode" = "Disattiva inclinazione"; 59 | "Suppressed Mode (IN2)" = "Modo Soppresso (IN2)"; 60 | "Point Mode" = "Modo Puntatore"; 61 | "Switch Stream Mode" = "Modo Continuo con interruttore"; 62 | "Stream Mode" = "Modo Continuo"; 63 | "Continuous Data Mode" = "Modo dati Continuo"; 64 | "Trailing Data Mode" = "Modo Dati trascinati"; 65 | "Normal Data Mode" = "Modo Dati Normali"; 66 | "Origin UL" = "Origine AS"; 67 | "Origin LL" = "Origine BS"; 68 | "Scale 15240 x 15240" = "Scala 15240 x 15240"; 69 | "Scale 32768 x 32768" = "Scala 32768 x 32768"; 70 | "Enable Pressure Mode" = "Attiva Pressione"; 71 | "Disable Pressure Mode" = "Disattiva Pressione"; 72 | "ASCII Data Mode" = "Modo Dati ASCII"; 73 | "Binary Data Mode" = "Modo Dati Binario"; 74 | "Enable Relative Mode" = "Attiva Modo Relativo"; 75 | "Disable Relative Mode" = "Disattiva Modo Relativo"; 76 | "Set 1000p/i Resolution" = "Fissa risoluzione a 1000p/i"; 77 | "Set 50p/mm Resolution" = "Fissa risoluzione a 50p/mm"; 78 | "Enable All Menu Buttons" = "Attiva tutti i Pulsanti del Menu"; 79 | "Disable Setup Button" = "Disattiva il Pulsante di Setup"; 80 | "Disable Function Buttons" = "Disattiva i Pulsanti Funzioni"; 81 | "Disable Pressure Buttons" = "Disattiva i Pulsanti di Pressione"; 82 | "Pressure Buttons as Macros" = "Pulsanti di Pressioni Sono Macro"; 83 | "BA Command" = "Comando BA"; 84 | "LA Command" = "Comando LA"; 85 | "CA Command" = "Comando CA"; 86 | "OR Command" = "Comando OR"; 87 | "RC Command" = "Comando RC"; 88 | "RS Command" = "Comando RS"; 89 | "SB Command" = "Comando SB"; 90 | "YR Command" = "Comando YR"; 91 | "AS Command" = "Comando AS"; 92 | "DE Command" = "Comando DE"; 93 | "IC Command" = "Comando IC"; 94 | "PH Command" = "Comando PH"; 95 | "SC Command" = "Comando SC"; 96 | 97 | 98 | /* Tablet Events */ 99 | "Pen Engaged" = "Penna Vicina"; 100 | "Pen Disengaged" = "Penna Lontana"; 101 | "Pen Down" = "Penna Giu'"; 102 | "Pen Up" = "Penna Su"; 103 | "Eraser Engaged" = "Eraser Vicino"; 104 | "Eraser Disengaged" = "Eraser Lontano"; 105 | "Eraser Down" = "Eraser Giu'"; 106 | "Eraser Up" = "Eraser Su"; 107 | "Button Click" = "Pulsante premuto"; 108 | "Button Release" = "Pulsante rilasciato"; 109 | 110 | -------------------------------------------------------------------------------- /prefpane/it.lproj/TabletMagicSearchGroups.searchTerms: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tabletmagicMain 6 | 7 | localizableStrings 8 | 9 | 10 | index 11 | wacom, tavolette, penna, digitalizzatore, seriale, ink 12 | title 13 | TabletMagic 14 | 15 | 16 | 17 | tabletmagicSetupTab 18 | 19 | localizableStrings 20 | 21 | 22 | index 23 | wacom, tavolette, setup, serial, origin, pressure, tilt, drawing 24 | title 25 | Impostazioni di TabletMagic 26 | 27 | 28 | 29 | tabletmagicMappingTab 30 | 31 | localizableStrings 32 | 33 | 34 | index 35 | mappatura, geometry, schermo, pulsante 36 | title 37 | Mappatura del TabletMagic 38 | 39 | 40 | 41 | tabletmagicTestingTab 42 | 43 | localizableStrings 44 | 45 | 46 | index 47 | test, try, monitor, log, logging, commandi 48 | title 49 | Test del TabletMagic 50 | 51 | 52 | 53 | tabletmagicExtrasTab 54 | 55 | localizableStrings 56 | 57 | 58 | index 59 | ink, daemon, tabletmagicdaemon 60 | title 61 | Supplementi di TabletMagic 62 | 63 | 64 | 65 | tabletmagicDonateTab 66 | 67 | localizableStrings 68 | 69 | 70 | index 71 | doni, github, oss, gpl 72 | title 73 | TabletMagic Donation 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /version.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildVersion 6 | 1 7 | CFBundleShortVersionString 8 | 1.0 9 | CFBundleVersion 10 | 1.0 11 | ProjectName 12 | PreferencePaneTemplate 13 | SourceVersion 14 | 270000 15 | 16 | 17 | --------------------------------------------------------------------------------