├── .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 |
--------------------------------------------------------------------------------