Rev 4 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | unit DXInput; |
2 | |||
3 | interface |
||
4 | |||
5 | {$INCLUDE DelphiXcfg.inc} |
||
6 | |||
7 | uses |
||
8 | Windows, Messages, SysUtils, Classes, Controls, Forms, MMSystem, |
||
9 | DirectX, DXClass; |
||
10 | |||
11 | type |
||
12 | |||
13 | { EDXInputError } |
||
14 | |||
15 | EDXInputError = class(Exception); |
||
16 | |||
17 | { EForceFeedbackEffectError } |
||
18 | |||
19 | EForceFeedbackEffectError = class(Exception); |
||
20 | |||
21 | |||
22 | { TForceFeedbackEffect } |
||
23 | |||
24 | TForceFeedbackEffectType = (etNone, etConstantForce, etPeriodic, etCondition); |
||
25 | |||
26 | TForceFeedbackEffect = class; |
||
27 | TForceFeedbackEffects = class; |
||
28 | |||
29 | TForceFeedbackEffectObject = class |
||
30 | private |
||
31 | FAxes: array[0..1] of DWORD; |
||
32 | FAxesCount: Integer; |
||
33 | Feff: TDIEffect; |
||
34 | FDirections: array[0..1] of DWORD; |
||
35 | FEnvelope: TDIEnvelope; |
||
36 | FConstantForce: TDIConstantForce; |
||
37 | FCondition: TDICondition; |
||
38 | FPeriodic: TDIPeriodic; |
||
39 | FEffect: IDirectInputEffect; |
||
40 | procedure Clear; |
||
41 | procedure Init(Effect: TForceFeedbackEffect); |
||
42 | procedure Release; |
||
43 | public |
||
44 | destructor Destroy; override; |
||
45 | end; |
||
46 | |||
47 | TForceFeedbackEffect = class(TPersistent) |
||
48 | private |
||
49 | FRoot: TForceFeedbackEffects; |
||
50 | FParent: TForceFeedbackEffect; |
||
51 | FList: TList; |
||
52 | FAttackLevel: Integer; |
||
53 | FAttackTime: Integer; |
||
54 | FCondition: TPoint; |
||
55 | FConstant: TPoint; |
||
56 | FEffectType: TForceFeedbackEffectType; |
||
57 | FFadeLevel: Integer; |
||
58 | FFadeTime: Integer; |
||
59 | FName: string; |
||
60 | FPeriod: Integer; |
||
61 | FPlaying: Boolean; |
||
62 | FPower: Integer; |
||
63 | FTime: Integer; |
||
64 | FStartDelayTime: Integer; |
||
65 | FObject: TForceFeedbackEffectObject; |
||
66 | FObject2: TForceFeedbackEffectObject; |
||
67 | FFindEffectFlag: Boolean; |
||
68 | FFindEffectGUID: TGUID; |
||
69 | procedure Acquire; |
||
70 | procedure Finalize; |
||
71 | procedure Initialize; |
||
72 | procedure ChangeEffect; |
||
73 | procedure MakeEff; |
||
74 | procedure CreateEffect; |
||
75 | function GetCount: Integer; |
||
76 | function GetEffect(Index: Integer): TForceFeedbackEffect; |
||
77 | function GetIndex: Integer; |
||
78 | function GetPlaying: Boolean; |
||
79 | procedure SetAttackLevel(Value: Integer); |
||
80 | procedure SetAttackTime(Value: Integer); |
||
81 | procedure SetCondition(Value: TPoint); |
||
82 | procedure SetConstant(Value: TPoint); |
||
83 | procedure SetEffectType(Value: TForceFeedbackEffectType); |
||
84 | procedure SetFadeLevel(Value: Integer); |
||
85 | procedure SetFadeTime(Value: Integer); |
||
86 | procedure SetIndex(Value: Integer); |
||
87 | procedure SetPeriod(Value: Integer); |
||
88 | procedure SetParent(Value: TForceFeedbackEffect); |
||
89 | procedure SetPower(Value: Integer); |
||
90 | procedure SetTime(Value: Integer); |
||
91 | procedure SetStartDelayTime(Value: Integer); |
||
92 | function HasInterface: Boolean; |
||
93 | protected |
||
94 | function GetOwner: TPersistent; override; |
||
95 | property StartDelayTime: Integer read FStartDelayTime write SetStartDelayTime; |
||
96 | public |
||
97 | constructor Create(AParent: TForceFeedbackEffect); |
||
98 | destructor Destroy; override; |
||
99 | procedure Assign(Source: TPersistent); override; |
||
100 | procedure Clear; |
||
101 | function Find(const Name: string): TForceFeedbackEffect; |
||
102 | function IndexOf(const Name: string): Integer; |
||
103 | procedure LoadFromFile(const FileName: string); |
||
104 | procedure LoadFromStream(Stream: TStream); |
||
105 | procedure SaveToFile(const FileName: string); |
||
106 | procedure SaveToStream(Stream: TStream); |
||
107 | procedure Start; |
||
108 | procedure Stop; |
||
109 | procedure Unload(Recurse: Boolean); |
||
110 | property Count: Integer read GetCount; |
||
111 | property Effects[Index: Integer]: TForceFeedbackEffect read GetEffect; default; |
||
112 | property Index: Integer read GetIndex write SetIndex; |
||
113 | property Playing: Boolean read GetPlaying; |
||
114 | property Parent: TForceFeedbackEffect read FParent write SetParent; |
||
115 | property Name: string read FName write FName; |
||
116 | property EffectType: TForceFeedbackEffectType read FEffectType write SetEffectType; |
||
117 | property AttackLevel: Integer read FAttackLevel write SetAttackLevel; |
||
118 | property AttackTime: Integer read FAttackTime write SetAttackTime; |
||
119 | property Condition: TPoint read FCondition write SetCondition; |
||
120 | property Constant: TPoint read FConstant write SetConstant; |
||
121 | property FadeLevel: Integer read FFadeLevel write SetFadeLevel; |
||
122 | property FadeTime: Integer read FFadeTime write SetFadeTime; |
||
123 | property Period: Integer read FPeriod write SetPeriod; |
||
124 | property Power: Integer read FPower write SetPower; |
||
125 | property Time: Integer read FTime write SetTime; |
||
126 | end; |
||
127 | |||
128 | { TForceFeedbackEffects } |
||
129 | |||
130 | TCustomInput = class; |
||
131 | |||
132 | TForceFeedbackEffects = class(TForceFeedbackEffect) |
||
133 | private |
||
134 | FComponent: TComponent; |
||
135 | FInput: TCustomInput; |
||
136 | protected |
||
137 | procedure DefineProperties(Filer: TFiler); override; |
||
138 | public |
||
139 | constructor Create(Input: TCustomInput); |
||
140 | destructor Destroy; override; |
||
141 | property Input: TCustomInput read FInput; |
||
142 | end; |
||
143 | |||
144 | { TCustomInput } |
||
145 | |||
146 | TDXInputState = (isUp, isDown, isLeft, isRight, isButton1, isButton2, isButton3, |
||
147 | isButton4, isButton5, isButton6, isButton7, isButton8, isButton9, isButton10, isButton11, |
||
148 | isButton12, isButton13, isButton14, isButton15, isButton16, isButton17, isButton18, |
||
149 | isButton19, isButton20, isButton21, isButton22, isButton23, isButton24, isButton25, |
||
150 | isButton26, isButton27, isButton28, isButton29, isButton30, isButton31, isButton32); |
||
151 | |||
152 | TDXInputStates = set of TDXInputState; |
||
153 | |||
154 | TCustomDXInput = class; |
||
155 | |||
156 | TCustomInput = class(TPersistent) |
||
157 | private |
||
158 | FBindInputStates: Boolean; |
||
159 | FButtonCount: Integer; |
||
160 | FDataFormat: TDIDataFormat; |
||
161 | FDataFormatObjects: array[0..255] of TDIObjectDataFormat; |
||
162 | FDataFormatGUIDs: array[0..255] of TGUID; |
||
163 | FDevice: IDirectInputDevice; |
||
164 | FDevice2: IDirectInputDevice2; |
||
165 | FDXInput: TCustomDXInput; |
||
166 | FEffects: TForceFeedbackEffects; |
||
167 | FEnabled: Boolean; |
||
168 | FForceFeedback: Boolean; |
||
169 | FForceFeedbackDevice: Boolean; |
||
170 | FInitialized: Boolean; |
||
171 | FStates: TDXInputStates; |
||
172 | procedure Acquire; |
||
173 | procedure Finalize; virtual; |
||
174 | procedure Initialize; virtual; |
||
175 | function GetButton(Index: Integer): Boolean; |
||
176 | function GetCooperativeLevel: Integer; virtual; |
||
177 | function GetDeviceState(dwSize: Integer; var Data): Boolean; |
||
178 | function SetDataFormat: Boolean; |
||
179 | procedure SetEffects(Value: TForceFeedbackEffects); |
||
180 | procedure SetEnabled(Value: Boolean); |
||
181 | procedure SetForceFeedback(Value: Boolean); |
||
182 | procedure SetWindowHandle(Value: Integer); |
||
183 | public |
||
184 | constructor Create(DXInput: TCustomDXInput); virtual; |
||
185 | destructor Destroy; override; |
||
186 | procedure Update; virtual; abstract; |
||
187 | property ButtonCount: Integer read FButtonCount; |
||
188 | property Buttons[Index: Integer]: Boolean read GetButton; |
||
189 | property States: TDXInputStates read FStates; |
||
190 | published |
||
191 | property BindInputStates: Boolean read FBindInputStates write FBindInputStates; |
||
192 | property Effects: TForceFeedbackEffects read FEffects write SetEffects; |
||
193 | property Enabled: Boolean read FEnabled write SetEnabled; |
||
194 | property ForceFeedback: Boolean read FForceFeedback write SetForceFeedback; |
||
195 | end; |
||
196 | |||
197 | { TKeyboard } |
||
198 | |||
199 | PKeyAssign = ^TKeyAssign; |
||
200 | TKeyAssign = array[0..2] of Integer; |
||
201 | |||
202 | TKeyAssignList = array[TDXInputState] of TKeyAssign; |
||
203 | |||
204 | TKeyboard = class(TCustomInput) |
||
205 | private |
||
206 | FKeyStates: TKeyboardState; |
||
207 | procedure Finalize; override; |
||
208 | procedure Initialize; override; |
||
209 | function GetKey(Key: Integer): Boolean; |
||
210 | procedure ReadAssigns(Stream: TStream); |
||
211 | procedure WriteAssigns(Stream: TStream); |
||
212 | protected |
||
213 | procedure DefineProperties(Filer: TFiler); override; |
||
214 | public |
||
215 | KeyAssigns: TKeyAssignList; |
||
216 | constructor Create(DXInput: TCustomDXInput); override; |
||
217 | procedure Update; override; |
||
218 | property Keys[Key: Integer]: Boolean read GetKey; |
||
219 | end; |
||
220 | |||
221 | { TMouse } |
||
222 | |||
223 | TMouse = class(TCustomInput) |
||
224 | private |
||
225 | Fdims: TDIMouseState; |
||
226 | procedure Finalize; override; |
||
227 | procedure Initialize; override; |
||
228 | function GetX: Integer; |
||
229 | function GetY: Integer; |
||
230 | function GetZ: Integer; |
||
231 | public |
||
232 | constructor Create(DXInput: TCustomDXInput); override; |
||
233 | procedure Update; override; |
||
234 | property X: Integer read GetX; |
||
235 | property Y: Integer read GetY; |
||
236 | property Z: Integer read GetZ; |
||
237 | end; |
||
238 | |||
239 | { TJoystick } |
||
240 | |||
241 | TJoystick = class(TCustomInput) |
||
242 | private |
||
243 | Fdijs: TDIJoyState2; |
||
244 | FAutoCenter: Boolean; |
||
245 | FDeviceGUID: TGUID; |
||
246 | FEnumFlag: Boolean; |
||
247 | FEnumIndex: Integer; |
||
248 | FID: Integer; |
||
249 | FID2: Integer; |
||
250 | FJoyCaps: TJoyCaps; |
||
251 | FDeadZone: array[0..SizeOf(TDIJoyState2)-1] of Integer; |
||
252 | FRange: array[0..SizeOf(TDIJoyState2)-1] of Integer; |
||
253 | procedure Finalize; override; |
||
254 | procedure Initialize; override; |
||
255 | function GetCooperativeLevel: Integer; override; |
||
256 | function GetDeadZone(Obj: Integer): Integer; |
||
257 | function GetRange(Obj: Integer): Integer; |
||
258 | function GetX: Integer; |
||
259 | function GetY: Integer; |
||
260 | function GetZ: Integer; |
||
261 | procedure SetDeadZone(Obj: Integer; Value: Integer); |
||
262 | procedure SetRange(Obj: Integer; Value: Integer); |
||
263 | procedure SetAutoCenter(Value: Boolean); |
||
264 | procedure SetID(Value: Integer); |
||
265 | public |
||
266 | constructor Create(DXInput: TCustomDXInput); override; |
||
267 | procedure Update; override; |
||
268 | property DeadZone[Obj: Integer]: Integer read GetDeadZone write SetDeadZone; |
||
269 | property Range[Obj: Integer]: Integer read GetRange write SetRange; |
||
270 | property Joystate: TDIJoyState2 read Fdijs; |
||
271 | property X: Integer read GetX; |
||
272 | property Y: Integer read GetY; |
||
273 | property Z: Integer read GetZ; |
||
274 | published |
||
275 | property AutoCenter: Boolean read FAutoCenter write SetAutoCenter; |
||
276 | property DeadZoneX: Integer index DIJOFS_X read GetDeadZone write SetDeadZone; |
||
277 | property DeadZoneY: Integer index DIJOFS_Y read GetDeadZone write SetDeadZone; |
||
278 | property DeadZoneZ: Integer index DIJOFS_Z read GetDeadZone write SetDeadZone; |
||
279 | property ID: Integer read FID write SetID; |
||
280 | property RangeX: Integer index DIJOFS_X read GetRange write SetRange; |
||
281 | property RangeY: Integer index DIJOFS_Y read GetRange write SetRange; |
||
282 | property RangeZ: Integer index DIJOFS_Z read GetRange write SetRange; |
||
283 | end; |
||
284 | |||
285 | { TCustomDXInput } |
||
286 | |||
287 | TCustomDXInput = class(TComponent) |
||
288 | private |
||
289 | FActiveOnly: Boolean; |
||
290 | FDevice: TList; |
||
291 | FDInput: IDirectInput; |
||
292 | FForm: TCustomForm; |
||
293 | FJoystick: TJoystick; |
||
294 | FKeyboard: TKeyboard; |
||
295 | FMouse: TMouse; |
||
296 | FOldStates: TDXInputStates; |
||
297 | FStates: TDXInputStates; |
||
298 | FSubClass: TControlSubClass; |
||
299 | FUseDirectInput: Boolean; |
||
300 | procedure Finalize; |
||
301 | procedure Initialize; |
||
302 | procedure FormWndProc(var Message: TMessage; DefWindowProc: TWndMethod); |
||
303 | procedure SetActiveOnly(Value: Boolean); |
||
304 | procedure SetJoystick(Value: TJoystick); |
||
305 | procedure SetKeyboard(Value: TKeyboard); |
||
306 | procedure SetMouse(Value: TMouse); |
||
307 | procedure SetWindowHandle; |
||
308 | procedure SetUseDirectInput(Value: Boolean); |
||
309 | protected |
||
310 | procedure Loaded; override; |
||
311 | public |
||
312 | constructor Create(AOwner: TComponent); override; |
||
313 | destructor Destroy; override; |
||
314 | procedure Update; |
||
315 | property ActiveOnly: Boolean read FActiveOnly write SetActiveOnly; |
||
316 | property Joystick: TJoystick read FJoystick write SetJoystick; |
||
317 | property Keyboard: TKeyboard read FKeyboard write SetKeyboard; |
||
318 | property Mouse: TMouse read FMouse write SetMouse; |
||
319 | property States: TDXInputStates read FStates write FStates; |
||
320 | property UseDirectInput: Boolean read FUseDirectInput write SetUseDirectInput; |
||
321 | end; |
||
322 | |||
323 | { TDXInput } |
||
324 | |||
325 | TDXInput = class(TCustomDXInput) |
||
326 | published |
||
327 | property ActiveOnly; |
||
328 | property Joystick; |
||
329 | property Keyboard; |
||
330 | property Mouse; |
||
331 | property UseDirectInput; |
||
332 | end; |
||
333 | |||
334 | function DefKeyAssign: TKeyAssignList; |
||
335 | function DefKeyAssign2_1: TKeyAssignList; |
||
336 | function DefKeyAssign2_2: TKeyAssignList; |
||
337 | |||
338 | implementation |
||
339 | |||
340 | uses DXConsts; |
||
341 | |||
342 | procedure AssignKey(var KeyAssignList: TKeyAssignList; State: TDXInputState; |
||
343 | const Keys: array of Integer); |
||
344 | var |
||
345 | i, i2: Integer; |
||
346 | KeyAssign: PKeyAssign; |
||
347 | begin |
||
348 | KeyAssign := @KeyAssignList[State]; |
||
349 | FillChar(KeyAssign^, SizeOf(TKeyAssign), 0); |
||
350 | |||
351 | i2 := 0; |
||
352 | for i:=LOW(Keys) to HIGH(Keys) do |
||
353 | begin |
||
354 | if i2<3 then |
||
355 | KeyAssign^[i2] := Keys[i] |
||
356 | else |
||
357 | Exit; |
||
358 | Inc(i2); |
||
359 | end; |
||
360 | end; |
||
361 | |||
362 | function DefKeyAssign: TKeyAssignList; |
||
363 | begin |
||
364 | FillChar(Result, SizeOf(Result), 0); |
||
365 | |||
366 | AssignKey(Result, isUp, [Ord('K'), VK_UP, VK_NUMPAD8]); |
||
367 | AssignKey(Result, isDown, [Ord('J'), VK_DOWN, VK_NUMPAD2]); |
||
368 | AssignKey(Result, isLeft, [Ord('H'), VK_LEFT, VK_NUMPAD4]); |
||
369 | AssignKey(Result, isRight, [Ord('L'), VK_RIGHT, VK_NUMPAD6]); |
||
370 | AssignKey(Result, isButton1, [Ord('Z'), VK_SPACE]); |
||
371 | AssignKey(Result, isButton2, [Ord('X'), VK_RETURN]); |
||
372 | AssignKey(Result, isButton9, [VK_F2]); |
||
373 | end; |
||
374 | |||
375 | function DefKeyAssign2_1: TKeyAssignList; |
||
376 | begin |
||
377 | FillChar(Result, SizeOf(Result), 0); |
||
378 | |||
379 | AssignKey(Result, isUp, [Ord('K'), VK_UP, VK_NUMPAD8]); |
||
380 | AssignKey(Result, isDown, [Ord('J'), VK_DOWN, VK_NUMPAD2]); |
||
381 | AssignKey(Result, isLeft, [Ord('H'), VK_LEFT, VK_NUMPAD4]); |
||
382 | AssignKey(Result, isRight, [Ord('L'), VK_RIGHT, VK_NUMPAD6]); |
||
383 | AssignKey(Result, isButton1, [VK_SPACE , VK_NUMPAD0]); |
||
384 | AssignKey(Result, isButton2, [VK_RETURN, VK_NUMPAD5]); |
||
385 | AssignKey(Result, isButton9, [VK_F2]); |
||
386 | end; |
||
387 | |||
388 | function DefKeyAssign2_2: TKeyAssignList; |
||
389 | begin |
||
390 | FillChar(Result, SizeOf(Result), 0); |
||
391 | |||
392 | AssignKey(Result, isUp, [Ord('E')]); |
||
393 | AssignKey(Result, isDown, [Ord('C')]); |
||
394 | AssignKey(Result, isLeft, [Ord('S')]); |
||
395 | AssignKey(Result, isRight, [Ord('F')]); |
||
396 | AssignKey(Result, isButton1, [Ord('Z')]); |
||
397 | AssignKey(Result, isButton2, [Ord('X')]); |
||
398 | AssignKey(Result, isButton9, [VK_F2]); |
||
399 | end; |
||
400 | |||
401 | { TForceFeedbackEffectObject } |
||
402 | |||
403 | destructor TForceFeedbackEffectObject.Destroy; |
||
404 | begin |
||
405 | Release; |
||
406 | inherited Destroy; |
||
407 | end; |
||
408 | |||
409 | function ConvertTime(i: Integer): DWORD; |
||
410 | begin |
||
411 | if i=-1 then Result := INFINITE else Result := i*1000; |
||
412 | end; |
||
413 | |||
414 | procedure TForceFeedbackEffectObject.Clear; |
||
415 | begin |
||
416 | FillChar(Feff, SizeOf(Feff), 0); |
||
417 | end; |
||
418 | |||
419 | procedure TForceFeedbackEffectObject.Init(Effect: TForceFeedbackEffect); |
||
420 | begin |
||
421 | with FEnvelope do |
||
422 | begin |
||
423 | dwSize := SizeOf(FEnvelope); |
||
424 | |||
425 | dwAttackLevel := Effect.FAttackLevel; |
||
426 | if Effect.FTime<0 then |
||
427 | dwAttackTime := Effect.FAttackTime*1000 |
||
428 | else |
||
429 | dwAttackTime := Min(Effect.FAttackTime, Effect.FTime)*1000; |
||
430 | |||
431 | if Effect.FTime<0 then |
||
432 | begin |
||
433 | dwFadeLevel := 0; |
||
434 | dwFadeTime := 0; |
||
435 | end else |
||
436 | begin |
||
437 | dwFadeLevel := Effect.FFadeLevel; |
||
438 | dwFadeTime := Min(Effect.FFadeTime, Effect.FTime)*1000; |
||
439 | end; |
||
440 | end; |
||
441 | |||
442 | FillChar(Feff, SizeOf(Feff), 0); |
||
443 | with Feff do |
||
444 | begin |
||
445 | dwSize := SizeOf(Feff); |
||
446 | dwFlags := DIEFF_CARTESIAN or DIEFF_OBJECTOFFSETS; |
||
447 | dwDuration := ConvertTime(Effect.FTime); |
||
448 | dwSamplePeriod := 0; |
||
449 | dwGain := Effect.FPower; |
||
450 | dwTriggerButton := DIEB_NOTRIGGER; |
||
451 | dwTriggerRepeatInterval := 0; |
||
452 | cAxes := FAxesCount; |
||
453 | rgdwAxes := @FAxes; |
||
454 | rglDirection := @FDirections; |
||
455 | lpEnvelope := @FEnvelope; |
||
456 | //dwStartDelay := Effect.FStartDelayTime; |
||
457 | end; |
||
458 | end; |
||
459 | |||
460 | procedure TForceFeedbackEffectObject.Release; |
||
461 | begin |
||
462 | FEffect := nil; |
||
463 | end; |
||
464 | |||
465 | { TForceFeedbackEffect } |
||
466 | |||
467 | constructor TForceFeedbackEffect.Create(AParent: TForceFeedbackEffect); |
||
468 | begin |
||
469 | inherited Create; |
||
470 | FParent := AParent; |
||
471 | FList := TList.Create; |
||
472 | |||
473 | if FParent<>nil then |
||
474 | begin |
||
475 | FParent.FList.Add(Self); |
||
476 | FRoot := FParent.FRoot; |
||
477 | end else |
||
478 | begin |
||
479 | FName := 'Effects'; |
||
480 | FRoot := Self as TForceFeedbackEffects; |
||
481 | end; |
||
482 | |||
483 | FObject := TForceFeedbackEffectObject.Create; |
||
484 | FObject2 := TForceFeedbackEffectObject.Create; |
||
485 | |||
486 | AttackTime := 0; |
||
487 | Constant := Point(0, 0); |
||
488 | EffectType := etNone; |
||
489 | FadeTime := 0; |
||
490 | Period := 50; |
||
491 | Power := 10000; |
||
492 | Time := 1000; |
||
493 | end; |
||
494 | |||
495 | destructor TForceFeedbackEffect.Destroy; |
||
496 | begin |
||
497 | Clear; |
||
498 | FObject.Free; |
||
499 | FObject2.Free; |
||
500 | FList.Free; |
||
501 | if FParent<>nil then |
||
502 | FParent.FList.Remove(Self); |
||
503 | inherited Destroy; |
||
504 | end; |
||
505 | |||
506 | function TForceFeedbackEffect.GetOwner: TPersistent; |
||
507 | begin |
||
508 | Result := Parent; |
||
509 | end; |
||
510 | |||
511 | procedure TForceFeedbackEffect.Assign(Source: TPersistent); |
||
512 | var |
||
513 | i: Integer; |
||
514 | begin |
||
515 | if Source is TForceFeedbackEffect then |
||
516 | begin |
||
517 | if Source<>Self then |
||
518 | begin |
||
519 | Clear; |
||
520 | |||
521 | EffectType := etNone; |
||
522 | |||
523 | Name := TForceFeedbackEffect(Source).Name; |
||
524 | |||
525 | AttackLevel := TForceFeedbackEffect(Source).AttackLevel; |
||
526 | AttackTime := TForceFeedbackEffect(Source).AttackTime; |
||
527 | Constant := TForceFeedbackEffect(Source).Constant; |
||
528 | Condition := TForceFeedbackEffect(Source).Condition; |
||
529 | EffectType := TForceFeedbackEffect(Source).EffectType; |
||
530 | FadeLevel := TForceFeedbackEffect(Source).FadeLevel; |
||
531 | FadeTime := TForceFeedbackEffect(Source).FadeTime; |
||
532 | Period := TForceFeedbackEffect(Source).Period; |
||
533 | Power := TForceFeedbackEffect(Source).Power; |
||
534 | Time := TForceFeedbackEffect(Source).Time; |
||
535 | StartDelayTime := TForceFeedbackEffect(Source).StartDelayTime; |
||
536 | |||
537 | EffectType := TForceFeedbackEffect(Source).EffectType; |
||
538 | |||
539 | for i:=0 to TForceFeedbackEffect(Source).Count-1 do |
||
540 | TForceFeedbackEffect.Create(Self).Assign(TForceFeedbackEffect(Source)[i]); |
||
541 | end; |
||
542 | end else |
||
543 | inherited Assign(Source); |
||
544 | end; |
||
545 | |||
546 | procedure TForceFeedbackEffect.Acquire; |
||
547 | var |
||
548 | i: Integer; |
||
549 | begin |
||
550 | if Playing and (Time=-1) then |
||
551 | Start; |
||
552 | |||
553 | for i:=0 to Count-1 do |
||
554 | Effects[i].Initialize; |
||
555 | end; |
||
556 | |||
557 | procedure TForceFeedbackEffect.Clear; |
||
558 | begin |
||
559 | while Count>0 do |
||
560 | Effects[Count-1].Free; |
||
561 | end; |
||
562 | |||
563 | procedure TForceFeedbackEffect.Initialize; |
||
564 | var |
||
565 | i: Integer; |
||
566 | begin |
||
567 | CreateEffect; |
||
568 | for i:=0 to Count-1 do |
||
569 | Effects[i].Initialize; |
||
570 | end; |
||
571 | |||
572 | procedure TForceFeedbackEffect.Finalize; |
||
573 | var |
||
574 | i: Integer; |
||
575 | begin |
||
576 | try |
||
577 | Stop; |
||
578 | FObject.Release; |
||
579 | FObject2.Release; |
||
580 | finally |
||
581 | for i:=0 to Count-1 do |
||
582 | Effects[i].Finalize; |
||
583 | end; |
||
584 | end; |
||
585 | |||
586 | function TForceFeedbackEffect.Find(const Name: string): TForceFeedbackEffect; |
||
587 | var |
||
588 | i, p: Integer; |
||
589 | Effect: TForceFeedbackEffect; |
||
590 | AName: string; |
||
591 | begin |
||
592 | AName := Name; |
||
593 | Effect := Self; |
||
594 | |||
595 | p := AnsiPos('.', AName); |
||
596 | while p<>0 do |
||
597 | begin |
||
598 | i := Effect.IndexOf(AName); |
||
599 | if i<>-1 then |
||
600 | begin |
||
601 | Result := Effect[i]; |
||
602 | Exit; |
||
603 | end else |
||
604 | begin |
||
605 | i := Effect.IndexOf(Copy(Name, 1, p-1)); |
||
606 | if i=-1 then |
||
607 | raise EForceFeedbackEffectError.CreateFmt(SEffectNotFound, [Name]); |
||
608 | Effect := Effect[i]; |
||
609 | AName := Copy(Name, p+1, MaxInt); |
||
610 | p := AnsiPos('.', AName); |
||
611 | end; |
||
612 | end; |
||
613 | |||
614 | i := Effect.IndexOf(Name); |
||
615 | if i=-1 then |
||
616 | raise EForceFeedbackEffectError.CreateFmt(SEffectNotFound, [Name]); |
||
617 | Result := Effect[i]; |
||
618 | end; |
||
619 | |||
620 | function TForceFeedbackEffect.IndexOf(const Name: string): Integer; |
||
621 | var |
||
622 | i: Integer; |
||
623 | begin |
||
624 | Result := -1; |
||
625 | for i:=0 to Count-1 do |
||
626 | if Effects[i].Name=Name then |
||
627 | begin |
||
628 | Result := i; |
||
629 | Break; |
||
630 | end; |
||
631 | end; |
||
632 | |||
633 | function TForceFeedbackEffect.HasInterface: Boolean; |
||
634 | begin |
||
635 | Result := (FEffectType<>etNone) and ((FObject.FEffect<>nil) or (FObject2.FEffect<>nil)); |
||
636 | end; |
||
637 | |||
638 | procedure TForceFeedbackEffect.MakeEff; |
||
639 | var |
||
640 | Constant2: TPoint; |
||
641 | begin |
||
642 | FObject.Clear; |
||
643 | FObject2.Clear; |
||
644 | |||
645 | with Constant2 do |
||
646 | begin |
||
647 | X := -FConstant.X; |
||
648 | Y := -FConstant.Y; |
||
649 | end; |
||
650 | |||
651 | case FEffectType of |
||
652 | etConstantForce: { etConstantForce } |
||
653 | begin |
||
654 | with FObject do |
||
655 | begin |
||
656 | FDirections[0] := Constant2.X; |
||
657 | FDirections[1] := Constant2.Y; |
||
658 | |||
659 | FAxesCount := 2; |
||
660 | FAxes[0] := DIJOFS_X; |
||
661 | FAxes[1] := DIJOFS_Y; |
||
662 | |||
663 | with Constant2 do |
||
664 | FConstantForce.lMagnitude := Trunc(Sqrt(X*X+Y*Y)); |
||
665 | |||
666 | Init(Self); |
||
667 | with Feff do |
||
668 | begin |
||
669 | cbTypeSpecificParams := SizeOf(FConstantForce); |
||
670 | lpvTypeSpecificParams := @FConstantForce; |
||
671 | end; |
||
672 | end; |
||
673 | end; |
||
674 | etPeriodic: { etPeriodic } |
||
675 | begin |
||
676 | with FObject do |
||
677 | begin |
||
678 | FDirections[0] := Constant2.X; |
||
679 | FDirections[1] := Constant2.Y; |
||
680 | |||
681 | FAxesCount := 2; |
||
682 | FAxes[0] := DIJOFS_X; |
||
683 | FAxes[1] := DIJOFS_Y; |
||
684 | |||
685 | with FPeriodic do |
||
686 | begin |
||
687 | with Constant2 do |
||
688 | dwMagnitude := Trunc(Sqrt(X*X+Y*Y)); |
||
689 | lOffset := 0; |
||
690 | dwPhase := 0; |
||
691 | dwPeriod := ConvertTime(FPeriod); |
||
692 | end; |
||
693 | |||
694 | Init(Self); |
||
695 | with Feff do |
||
696 | begin |
||
697 | cbTypeSpecificParams := SizeOf(FPeriodic); |
||
698 | lpvTypeSpecificParams := @FPeriodic; |
||
699 | end; |
||
700 | end; |
||
701 | end; |
||
702 | etCondition: { etCondition } |
||
703 | begin |
||
704 | with FObject do |
||
705 | begin |
||
706 | FillChar(FDirections, SizeOf(FDirections), 0); |
||
707 | |||
708 | FAxesCount := 1; |
||
709 | FAxes[0] := DIJOFS_X; |
||
710 | |||
711 | with FCondition do |
||
712 | begin |
||
713 | lOffset := -Constant2.X; |
||
714 | lPositiveCoefficient := Self.FCondition.X; |
||
715 | lNegativeCoefficient := -Self.FCondition.X; |
||
716 | dwPositiveSaturation := 0; |
||
717 | dwNegativeSaturation := 0; |
||
718 | lDeadBand := 0; |
||
719 | end; |
||
720 | |||
721 | Init(Self); |
||
722 | with Feff do |
||
723 | begin |
||
724 | cbTypeSpecificParams := SizeOf(FCondition); |
||
725 | lpvTypeSpecificParams := @FCondition; |
||
726 | end; |
||
727 | end; |
||
728 | |||
729 | with FObject2 do |
||
730 | begin |
||
731 | FillChar(FDirections, SizeOf(FDirections), 0); |
||
732 | |||
733 | FAxesCount := 1; |
||
734 | FAxes[0] := DIJOFS_Y; |
||
735 | |||
736 | with FCondition do |
||
737 | begin |
||
738 | lOffset := -Constant2.Y; |
||
739 | lPositiveCoefficient := Self.FCondition.Y; |
||
740 | lNegativeCoefficient := -Self.FCondition.Y; |
||
741 | dwPositiveSaturation := 0; |
||
742 | dwNegativeSaturation := 0; |
||
743 | lDeadBand := 0; |
||
744 | end; |
||
745 | |||
746 | Init(Self); |
||
747 | with Feff do |
||
748 | begin |
||
749 | cbTypeSpecificParams := SizeOf(FCondition); |
||
750 | lpvTypeSpecificParams := @FCondition; |
||
751 | end; |
||
752 | end; |
||
753 | end; |
||
754 | end; |
||
755 | end; |
||
756 | |||
757 | procedure TForceFeedbackEffect.CreateEffect; |
||
758 | |||
759 | function FindEffectCallBack(const pdei: TDIEffectInfoA; |
||
760 | pvRef: Pointer): HRESULT; stdcall; |
||
761 | begin |
||
762 | with TForceFeedbackEffect(pvRef) do |
||
763 | begin |
||
764 | FFindEffectFlag := True; |
||
765 | FFindEffectGUID := pdei.guid; |
||
766 | end; |
||
767 | |||
768 | Result := DIENUM_STOP; |
||
769 | end; |
||
770 | |||
771 | procedure CreateIEffectGuid(const GUID: TGUID; |
||
772 | EffectObject: TForceFeedbackEffectObject); |
||
773 | begin |
||
774 | if EffectObject.Feff.dwSize=0 then Exit; |
||
775 | |||
776 | if FRoot.FInput.FDevice2<>nil then |
||
777 | FRoot.FInput.FDevice2.CreateEffect(GUID, EffectObject.Feff, EffectObject.FEffect, nil); |
||
778 | end; |
||
779 | |||
780 | procedure CreateIEffect(dwFlags: DWORD; |
||
781 | EffectObject: TForceFeedbackEffectObject); |
||
782 | begin |
||
783 | if EffectObject.Feff.dwSize=0 then Exit; |
||
784 | |||
785 | if FRoot.FInput.FDevice2<>nil then |
||
786 | begin |
||
787 | FFindEffectFlag := False; |
||
788 | FRoot.FInput.FDevice2.EnumEffects(@FindEffectCallBack, |
||
789 | Self, dwFlags); |
||
790 | if FFindEffectFlag then |
||
791 | CreateIEffectGuid(FFindEffectGUID, EffectObject); |
||
792 | end; |
||
793 | end; |
||
794 | |||
795 | begin |
||
796 | FObject.Release; |
||
797 | FObject2.Release; |
||
798 | |||
799 | if (FRoot.FInput=nil) or (FRoot.FInput.FDevice2=nil) or |
||
800 | (not FRoot.FInput.FForceFeedbackDevice) or |
||
801 | (not FRoot.FInput.FForceFeedback) then Exit; |
||
802 | |||
803 | if FEffectType=etNone then Exit; |
||
804 | |||
805 | MakeEff; |
||
806 | case FEffectType of |
||
807 | etConstantForce: |
||
808 | begin |
||
809 | CreateIEffectGUID(GUID_ConstantForce, FObject); |
||
810 | end; |
||
811 | etPeriodic: |
||
812 | begin |
||
813 | CreateIEffect(DIEFT_PERIODIC, FObject); |
||
814 | end; |
||
815 | etCondition: |
||
816 | begin |
||
817 | CreateIEffect(DIEFT_CONDITION, FObject); |
||
818 | CreateIEffect(DIEFT_CONDITION, FObject2); |
||
819 | end; |
||
820 | end; |
||
821 | |||
822 | if Playing and (Time=-1) then |
||
823 | Start; |
||
824 | end; |
||
825 | |||
826 | procedure TForceFeedbackEffect.ChangeEffect; |
||
827 | var |
||
828 | dwFlags: DWORD; |
||
829 | begin |
||
830 | if HasInterface then |
||
831 | begin |
||
832 | MakeEff; |
||
833 | |||
834 | dwFlags := DIEP_DIRECTION or DIEP_DURATION or DIEP_ENVELOPE or |
||
835 | DIEP_GAIN or DIEP_SAMPLEPERIOD or DIEP_TRIGGERBUTTON or |
||
836 | DIEP_TRIGGERREPEATINTERVAL or DIEP_TYPESPECIFICPARAMS; |
||
837 | |||
838 | if Playing then |
||
839 | dwFlags := dwFlags or DIEP_START; |
||
840 | |||
841 | if FObject.FEffect<>nil then FObject.FEffect.SetParameters(FObject.Feff, dwFlags); |
||
842 | if FObject2.FEffect<>nil then FObject2.FEffect.SetParameters(FObject2.Feff, dwFlags); |
||
843 | end; |
||
844 | end; |
||
845 | |||
846 | function TForceFeedbackEffect.GetPlaying: Boolean; |
||
847 | var |
||
848 | dwFlags: DWORD; |
||
849 | begin |
||
850 | Result := False; |
||
851 | |||
852 | if not FPlaying then Exit; |
||
853 | |||
854 | if FPlaying and (FTime=-1) then |
||
855 | begin |
||
856 | Result := True; |
||
857 | Exit; |
||
858 | end; |
||
859 | |||
860 | if FObject.FEffect<>nil then |
||
861 | begin |
||
862 | dwFlags := 0; |
||
863 | FObject.FEffect.GetEffectStatus(dwFlags); |
||
864 | if dwFlags and DIEGES_PLAYING<>0 then |
||
865 | begin |
||
866 | Result := True; |
||
867 | Exit; |
||
868 | end; |
||
869 | end; |
||
870 | |||
871 | if FObject2.FEffect<>nil then |
||
872 | begin |
||
873 | dwFlags := 0; |
||
874 | FObject2.FEffect.GetEffectStatus(dwFlags); |
||
875 | if dwFlags and DIEGES_PLAYING<>0 then |
||
876 | begin |
||
877 | Result := True; |
||
878 | Exit; |
||
879 | end; |
||
880 | end; |
||
881 | |||
882 | if not Result then |
||
883 | FPlaying := False; |
||
884 | end; |
||
885 | |||
886 | function TForceFeedbackEffect.GetCount: Integer; |
||
887 | begin |
||
888 | Result := FList.Count; |
||
889 | end; |
||
890 | |||
891 | function TForceFeedbackEffect.GetEffect(Index: Integer): TForceFeedbackEffect; |
||
892 | begin |
||
893 | Result :=FList[Index]; |
||
894 | end; |
||
895 | |||
896 | function TForceFeedbackEffect.GetIndex: Integer; |
||
897 | begin |
||
898 | if FParent<>nil then |
||
899 | Result := FParent.FList.IndexOf(Self) |
||
900 | else |
||
901 | Result := 0; |
||
902 | end; |
||
903 | |||
904 | procedure TForceFeedbackEffect.SetIndex(Value: Integer); |
||
905 | begin |
||
906 | if FParent<>nil then |
||
907 | begin |
||
908 | FParent.FList.Remove(Self); |
||
909 | FParent.FList.Insert(Value, Self); |
||
910 | end; |
||
911 | end; |
||
912 | |||
913 | procedure TForceFeedbackEffect.SetParent(Value: TForceFeedbackEffect); |
||
914 | begin |
||
915 | if Parent<>Value then |
||
916 | begin |
||
917 | if (Value=nil) or (FRoot<>Value.FRoot) then |
||
918 | raise EForceFeedbackEffectError.CreateFmt(SCannotChanged, ['Parent']); |
||
919 | |||
920 | FParent.FList.Remove(Self); |
||
921 | FParent := Value; |
||
922 | FParent.FList.Add(Self); |
||
923 | end; |
||
924 | end; |
||
925 | |||
926 | procedure TForceFeedbackEffect.SetAttackLevel(Value: Integer); |
||
927 | begin |
||
928 | if Value<0 then Value := 0; |
||
929 | if Value>10000 then Value := 10000; |
||
930 | |||
931 | if FAttackLevel<>Value then |
||
932 | begin |
||
933 | FAttackLevel := Value; |
||
934 | ChangeEffect; |
||
935 | end; |
||
936 | end; |
||
937 | |||
938 | procedure TForceFeedbackEffect.SetAttackTime(Value: Integer); |
||
939 | begin |
||
940 | if Value<0 then Value := 0; |
||
941 | |||
942 | if FAttackTime<>Value then |
||
943 | begin |
||
944 | FAttackTime := Value; |
||
945 | ChangeEffect; |
||
946 | end; |
||
947 | end; |
||
948 | |||
949 | procedure TForceFeedbackEffect.SetCondition(Value: TPoint); |
||
950 | begin |
||
951 | with Value do |
||
952 | begin |
||
953 | if X<-10000 then X := -10000; |
||
954 | if X>+10000 then X := +10000; |
||
955 | |||
956 | if Y<-10000 then Y := -10000; |
||
957 | if Y>+10000 then Y := +10000; |
||
958 | end; |
||
959 | |||
960 | if not CompareMem(@FCondition, @Value, SizeOf(FCondition)) then |
||
961 | begin |
||
962 | FCondition := Value; |
||
963 | |||
964 | if HasInterface then |
||
965 | ChangeEffect; |
||
966 | end; |
||
967 | end; |
||
968 | |||
969 | procedure TForceFeedbackEffect.SetConstant(Value: TPoint); |
||
970 | begin |
||
971 | with Value do |
||
972 | begin |
||
973 | if X<-10000 then X := -10000; |
||
974 | if X>+10000 then X := +10000; |
||
975 | |||
976 | if Y<-10000 then Y := -10000; |
||
977 | if Y>+10000 then Y := +10000; |
||
978 | end; |
||
979 | |||
980 | if not CompareMem(@FConstant, @Value, SizeOf(FConstant)) then |
||
981 | begin |
||
982 | FConstant := Value; |
||
983 | |||
984 | if HasInterface then |
||
985 | ChangeEffect; |
||
986 | end; |
||
987 | end; |
||
988 | |||
989 | procedure TForceFeedbackEffect.SetEffectType(Value: TForceFeedbackEffectType); |
||
990 | begin |
||
991 | if FEffectType<>Value then |
||
992 | begin |
||
993 | FEffectType := Value; |
||
994 | Stop; |
||
995 | CreateEffect; |
||
996 | end; |
||
997 | end; |
||
998 | |||
999 | procedure TForceFeedbackEffect.SetFadeLevel(Value: Integer); |
||
1000 | begin |
||
1001 | if Value<0 then Value := 0; |
||
1002 | if Value>10000 then Value := 10000; |
||
1003 | |||
1004 | if FFadeLevel<>Value then |
||
1005 | begin |
||
1006 | FFadeLevel := Value; |
||
1007 | ChangeEffect; |
||
1008 | end; |
||
1009 | end; |
||
1010 | |||
1011 | procedure TForceFeedbackEffect.SetFadeTime(Value: Integer); |
||
1012 | begin |
||
1013 | if Value<0 then Value := 0; |
||
1014 | |||
1015 | if FFadeTime<>Value then |
||
1016 | begin |
||
1017 | FFadeTime := Value; |
||
1018 | ChangeEffect; |
||
1019 | end; |
||
1020 | end; |
||
1021 | |||
1022 | procedure TForceFeedbackEffect.SetPeriod(Value: Integer); |
||
1023 | begin |
||
1024 | if Value<0 then Value := 0; |
||
1025 | |||
1026 | if FPeriod<>Value then |
||
1027 | begin |
||
1028 | FPeriod := Value; |
||
1029 | ChangeEffect; |
||
1030 | end; |
||
1031 | end; |
||
1032 | |||
1033 | procedure TForceFeedbackEffect.SetPower(Value: Integer); |
||
1034 | begin |
||
1035 | if Value<0 then Value := 0; |
||
1036 | if Value>10000 then Value := 10000; |
||
1037 | |||
1038 | if FPower<>Value then |
||
1039 | begin |
||
1040 | FPower := Value; |
||
1041 | ChangeEffect; |
||
1042 | end; |
||
1043 | end; |
||
1044 | |||
1045 | procedure TForceFeedbackEffect.SetTime(Value: Integer); |
||
1046 | begin |
||
1047 | if (Value<>-1) and (Value<0) then Value := 0; |
||
1048 | |||
1049 | if FTime<>Value then |
||
1050 | begin |
||
1051 | FTime := Value; |
||
1052 | Stop; |
||
1053 | ChangeEffect; |
||
1054 | end; |
||
1055 | end; |
||
1056 | |||
1057 | procedure TForceFeedbackEffect.SetStartDelayTime(Value: Integer); |
||
1058 | begin |
||
1059 | if Value<0 then Value := 0; |
||
1060 | |||
1061 | if FStartDelayTime<>Value then |
||
1062 | begin |
||
1063 | FStartDelayTime := Value; |
||
1064 | Stop; |
||
1065 | ChangeEffect; |
||
1066 | end; |
||
1067 | end; |
||
1068 | |||
1069 | procedure TForceFeedbackEffect.Start; |
||
1070 | |||
1071 | procedure StartEffect(Effect: IDirectInputEffect); |
||
1072 | var |
||
1073 | hr: HRESULT; |
||
1074 | begin |
||
1075 | if Effect<>nil then |
||
1076 | begin |
||
1077 | hr := Effect.Start(1, 0); |
||
1078 | if (hr=DIERR_INPUTLOST) or (hr=DIERR_NOTACQUIRED) then |
||
1079 | begin |
||
1080 | FRoot.FInput.Acquire; |
||
1081 | Effect.Start(1, 0); |
||
1082 | end; |
||
1083 | end; |
||
1084 | end; |
||
1085 | |||
1086 | var |
||
1087 | i: Integer; |
||
1088 | begin |
||
1089 | for i:=0 to Count-1 do |
||
1090 | Effects[i].Start; |
||
1091 | |||
1092 | if not HasInterface then |
||
1093 | begin |
||
1094 | CreateEffect; |
||
1095 | if not HasInterface then Exit; |
||
1096 | end; |
||
1097 | |||
1098 | StartEffect(FObject.FEffect); |
||
1099 | StartEffect(FObject2.FEffect); |
||
1100 | |||
1101 | FPlaying := True; |
||
1102 | end; |
||
1103 | |||
1104 | procedure TForceFeedbackEffect.Stop; |
||
1105 | var |
||
1106 | i: Integer; |
||
1107 | begin |
||
1108 | if Playing then |
||
1109 | begin |
||
1110 | FPlaying := False; |
||
1111 | if FObject.FEffect<>nil then FObject.FEffect.Stop; |
||
1112 | if FObject2.FEffect<>nil then FObject2.FEffect.Stop; |
||
1113 | end; |
||
1114 | |||
1115 | for i:=0 to Count-1 do |
||
1116 | Effects[i].Stop; |
||
1117 | end; |
||
1118 | |||
1119 | procedure TForceFeedbackEffect.Unload(Recurse: Boolean); |
||
1120 | var |
||
1121 | i: Integer; |
||
1122 | begin |
||
1123 | if Playing then |
||
1124 | begin |
||
1125 | if FObject.FEffect<>nil then FObject.FEffect.Stop; |
||
1126 | if FObject2.FEffect<>nil then FObject2.FEffect.Stop; |
||
1127 | end; |
||
1128 | |||
1129 | if FObject.FEffect<>nil then FObject.FEffect.Unload; |
||
1130 | if FObject2.FEffect<>nil then FObject2.FEffect.Unload; |
||
1131 | |||
1132 | if Recurse then |
||
1133 | begin |
||
1134 | for i:=0 to Count-1 do |
||
1135 | Effects[i].Unload(True); |
||
1136 | end; |
||
1137 | end; |
||
1138 | |||
1139 | type |
||
1140 | TForceFeedbackEffectItem = class(TCollectionItem) |
||
1141 | private |
||
1142 | FName: string; |
||
1143 | FEffectType: TForceFeedbackEffectType; |
||
1144 | FAttackLevel: Integer; |
||
1145 | FAttackTime: Integer; |
||
1146 | FConditionX: Integer; |
||
1147 | FConditionY: Integer; |
||
1148 | FConstantX: Integer; |
||
1149 | FConstantY: Integer; |
||
1150 | FFadeLevel: Integer; |
||
1151 | FFadeTime: Integer; |
||
1152 | FPeriod: Integer; |
||
1153 | FPower: Integer; |
||
1154 | FTime: Integer; |
||
1155 | FStartDelayTime: Integer; |
||
1156 | FEffects: TCollection; |
||
1157 | function GetStoredEffects: Boolean; |
||
1158 | public |
||
1159 | constructor Create(Collection: TCollection); override; |
||
1160 | destructor Destroy; override; |
||
1161 | procedure Assign(Source: TPersistent); override; |
||
1162 | procedure AssignTo(Dest: TPersistent); override; |
||
1163 | published |
||
1164 | property Name: string read FName write FName; |
||
1165 | property EffectType: TForceFeedbackEffectType read FEffectType write FEffectType; |
||
1166 | property AttackLevel: Integer read FAttackLevel write FAttackLevel default 0; |
||
1167 | property AttackTime: Integer read FAttackTime write FAttackTime default 0; |
||
1168 | property ConditionX: Integer read FConditionX write FConditionX default 0; |
||
1169 | property ConditionY: Integer read FConditionY write FConditionY default 0; |
||
1170 | property ConstantX: Integer read FConstantX write FConstantX default 0; |
||
1171 | property ConstantY: Integer read FConstantY write FConstantY default 0; |
||
1172 | property FadeLevel: Integer read FFadeLevel write FFadeLevel default 0; |
||
1173 | property FadeTime: Integer read FFadeTime write FFadeTime default 0; |
||
1174 | property Period: Integer read FPeriod write FPeriod; |
||
1175 | property Power: Integer read FPower write FPower; |
||
1176 | property Time: Integer read FTime write FTime; |
||
1177 | property StartDelayTime: Integer read FStartDelayTime write FStartDelayTime; |
||
1178 | property Effects: TCollection read FEffects write FEffects stored GetStoredEffects; |
||
1179 | end; |
||
1180 | |||
1181 | TForceFeedbackEffectComponent = class(TComponent) |
||
1182 | private |
||
1183 | FEffects: TCollection; |
||
1184 | published |
||
1185 | property Effects: TCollection read FEffects write FEffects; |
||
1186 | end; |
||
1187 | |||
1188 | constructor TForceFeedbackEffectItem.Create(Collection: TCollection); |
||
1189 | begin |
||
1190 | inherited Create(Collection); |
||
1191 | FEffects := TCollection.Create(TForceFeedbackEffectItem); |
||
1192 | end; |
||
1193 | |||
1194 | destructor TForceFeedbackEffectItem.Destroy; |
||
1195 | begin |
||
1196 | FEffects.Free; |
||
1197 | inherited Destroy; |
||
1198 | end; |
||
1199 | |||
1200 | procedure TForceFeedbackEffectItem.Assign(Source: TPersistent); |
||
1201 | var |
||
1202 | Effect: TForceFeedbackEffect; |
||
1203 | i: Integer; |
||
1204 | begin |
||
1205 | Effect := Source as TForceFeedbackEffect; |
||
1206 | |||
1207 | FName := Effect.Name; |
||
1208 | FEffectType := Effect.EffectType; |
||
1209 | FAttackLevel := Effect.AttackLevel; |
||
1210 | FAttackTime := Effect.AttackTime; |
||
1211 | FConditionX := Effect.Condition.X; |
||
1212 | FConditionY := Effect.Condition.Y; |
||
1213 | FConstantX := Effect.Constant.X; |
||
1214 | FConstantY := Effect.Constant.Y; |
||
1215 | FFadeLevel := Effect.FadeLevel; |
||
1216 | FFadeTime := Effect.FadeTime; |
||
1217 | FPeriod := Effect.Period; |
||
1218 | FPower := Effect.Power; |
||
1219 | FTime := Effect.Time; |
||
1220 | FStartDelayTime := Effect.StartDelayTime; |
||
1221 | |||
1222 | for i:=0 to Effect.Count-1 do |
||
1223 | TForceFeedbackEffectItem.Create(FEffects).Assign(Effect[i]); |
||
1224 | end; |
||
1225 | |||
1226 | procedure TForceFeedbackEffectItem.AssignTo(Dest: TPersistent); |
||
1227 | var |
||
1228 | Effect: TForceFeedbackEffect; |
||
1229 | i: Integer; |
||
1230 | begin |
||
1231 | Effect := Dest as TForceFeedbackEffect; |
||
1232 | |||
1233 | Effect.EffectType := etNone; |
||
1234 | |||
1235 | Effect.Name := FName; |
||
1236 | Effect.AttackLevel := FAttackLevel; |
||
1237 | Effect.AttackTime := FAttackTime; |
||
1238 | Effect.Condition := Point(FConditionX, FConditionY); |
||
1239 | Effect.Constant := Point(FConstantX, FConstantY); |
||
1240 | Effect.FadeLevel := FFadeLevel; |
||
1241 | Effect.FadeTime := FFadeTime; |
||
1242 | Effect.Period := FPeriod; |
||
1243 | Effect.Power := FPower; |
||
1244 | Effect.Time := FTime; |
||
1245 | Effect.StartDelayTime := FStartDelayTime; |
||
1246 | |||
1247 | Effect.EffectType := FEffectType; |
||
1248 | |||
1249 | for i:=0 to FEffects.Count-1 do |
||
1250 | TForceFeedbackEffectItem(FEffects.Items[i]).AssignTo(TForceFeedbackEffect.Create(Effect)); |
||
1251 | end; |
||
1252 | |||
1253 | function TForceFeedbackEffectItem.GetStoredEffects: Boolean; |
||
1254 | begin |
||
1255 | Result := FEffects.Count>0; |
||
1256 | end; |
||
1257 | |||
1258 | procedure TForceFeedbackEffect.LoadFromFile(const FileName: string); |
||
1259 | var |
||
1260 | Stream: TFileStream; |
||
1261 | begin |
||
1262 | Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); |
||
1263 | try |
||
1264 | LoadFromStream(Stream); |
||
1265 | finally |
||
1266 | Stream.Free; |
||
1267 | end; |
||
1268 | end; |
||
1269 | |||
1270 | procedure TForceFeedbackEffect.LoadFromStream(Stream: TStream); |
||
1271 | var |
||
1272 | Component: TForceFeedbackEffectComponent; |
||
1273 | begin |
||
1274 | Clear; |
||
1275 | |||
1276 | Component := TForceFeedbackEffectComponent(FRoot.FComponent); |
||
1277 | try |
||
1278 | Component.FEffects := TCollection.Create(TForceFeedbackEffectItem); |
||
1279 | Stream.ReadComponentRes(Component); |
||
1280 | TForceFeedbackEffectItem(Component.FEffects.Items[0]).AssignTo(Self); |
||
1281 | finally |
||
1282 | Component.FEffects.Free; |
||
1283 | Component.FEffects := nil; |
||
1284 | end; |
||
1285 | end; |
||
1286 | |||
1287 | procedure TForceFeedbackEffect.SaveToFile(const FileName: string); |
||
1288 | var |
||
1289 | Stream: TFileStream; |
||
1290 | begin |
||
1291 | Stream := TFileStream.Create(FileName, fmCreate); |
||
1292 | try |
||
1293 | SaveToStream(Stream); |
||
1294 | finally |
||
1295 | Stream.Free; |
||
1296 | end; |
||
1297 | end; |
||
1298 | |||
1299 | procedure TForceFeedbackEffect.SaveToStream(Stream: TStream); |
||
1300 | var |
||
1301 | Component: TForceFeedbackEffectComponent; |
||
1302 | begin |
||
1303 | Component := TForceFeedbackEffectComponent(FRoot.FComponent); |
||
1304 | try |
||
1305 | Component.FEffects := TCollection.Create(TForceFeedbackEffectItem); |
||
1306 | TForceFeedbackEffectItem.Create(Component.FEffects).Assign(Self); |
||
1307 | Stream.WriteComponentRes('DelphiXForceFeedbackEffect', Component); |
||
1308 | finally |
||
1309 | Component.FEffects.Free; |
||
1310 | Component.FEffects := nil; |
||
1311 | end; |
||
1312 | end; |
||
1313 | |||
1314 | { TForceFeedbackEffects } |
||
1315 | |||
1316 | constructor TForceFeedbackEffects.Create(Input: TCustomInput); |
||
1317 | begin |
||
1318 | inherited Create(nil); |
||
1319 | FInput := Input; |
||
1320 | FComponent := TForceFeedbackEffectComponent.Create(nil); |
||
1321 | end; |
||
1322 | |||
1323 | destructor TForceFeedbackEffects.Destroy; |
||
1324 | begin |
||
1325 | FComponent.Free; |
||
1326 | inherited Destroy; |
||
1327 | end; |
||
1328 | |||
1329 | procedure TForceFeedbackEffects.DefineProperties(Filer: TFiler); |
||
1330 | begin |
||
1331 | inherited DefineProperties(Filer); |
||
1332 | Filer.DefineBinaryProperty('Effects', LoadFromStream, SaveToStream, True); |
||
1333 | end; |
||
1334 | |||
1335 | { TCustomInput } |
||
1336 | |||
1337 | constructor TCustomInput.Create(DXInput: TCustomDXInput); |
||
1338 | begin |
||
1339 | inherited Create; |
||
1340 | FDXInput := DXInput; |
||
1341 | FDXInput.FDevice.Add(Self); |
||
1342 | FEffects := TForceFeedbackEffects.Create(Self); |
||
1343 | FEnabled := True; |
||
1344 | FBindInputStates := True; |
||
1345 | end; |
||
1346 | |||
1347 | destructor TCustomInput.Destroy; |
||
1348 | begin |
||
1349 | Finalize; |
||
1350 | FEffects.Free; |
||
1351 | FDXInput.FDevice.Remove(Self); |
||
1352 | inherited Destroy; |
||
1353 | end; |
||
1354 | |||
1355 | procedure TCustomInput.Acquire; |
||
1356 | begin |
||
1357 | if FDXInput.FActiveOnly and (GetForegroundWindow<>FDXInput.FForm.Handle) then |
||
1358 | Exit; |
||
1359 | |||
1360 | if FDevice<>nil then |
||
1361 | FDevice.Acquire; |
||
1362 | |||
1363 | FEffects.Acquire; |
||
1364 | end; |
||
1365 | |||
1366 | procedure TCustomInput.Finalize; |
||
1367 | begin |
||
1368 | if FDevice<>nil then FDevice.Unacquire; |
||
1369 | FInitialized := False; |
||
1370 | FButtonCount := 0; |
||
1371 | FEffects.Finalize; |
||
1372 | FDevice := nil; |
||
1373 | FDevice2 := nil; |
||
1374 | FForceFeedbackDevice := False; |
||
1375 | FStates := []; |
||
1376 | end; |
||
1377 | |||
1378 | procedure TCustomInput.Initialize; |
||
1379 | begin |
||
1380 | FInitialized := True; |
||
1381 | FEffects.Initialize; |
||
1382 | end; |
||
1383 | |||
1384 | function TCustomInput.GetButton(Index: Integer): Boolean; |
||
1385 | begin |
||
1386 | if Index in [0..31] then |
||
1387 | Result := TDXInputState(Integer(isButton1)+Index) in FStates |
||
1388 | else |
||
1389 | Result := False; |
||
1390 | end; |
||
1391 | |||
1392 | function TCustomInput.GetCooperativeLevel: Integer; |
||
1393 | const |
||
1394 | Levels: array[Boolean] of Integer = (DISCL_NONEXCLUSIVE, DISCL_EXCLUSIVE); |
||
1395 | Levels2: array[Boolean] of Integer = (DISCL_BACKGROUND, DISCL_FOREGROUND); |
||
1396 | begin |
||
1397 | Result := Levels[FForceFeedbackDevice and FForceFeedback] or Levels2[FDXInput.ActiveOnly]; |
||
1398 | end; |
||
1399 | |||
1400 | function TCustomInput.GetDeviceState(dwSize: Integer; var Data): Boolean; |
||
1401 | var |
||
1402 | hr: HRESULT; |
||
1403 | begin |
||
1404 | FillChar(Data, dwSize, 0); |
||
1405 | |||
1406 | if FDevice<>nil then |
||
1407 | begin |
||
1408 | hr := FDevice.GetDeviceState(dwSize, Data); |
||
1409 | if (hr=DIERR_INPUTLOST) or (hr=DIERR_NOTACQUIRED) then |
||
1410 | begin |
||
1411 | FDevice.Acquire; |
||
1412 | hr := FDevice.GetDeviceState(dwSize, Data); |
||
1413 | end; |
||
1414 | Result := hr=DI_OK; |
||
1415 | end else |
||
1416 | Result := False; |
||
1417 | end; |
||
1418 | |||
1419 | function TCustomInput.SetDataFormat: Boolean; |
||
1420 | |||
1421 | function DIEnumDeviceObjectsProc(const peff: TDIDeviceObjectInstanceA; |
||
1422 | pvRef: Pointer): HRESULT; stdcall; |
||
1423 | begin |
||
1424 | Result := DIENUM_CONTINUE; |
||
1425 | |||
1426 | if CompareMem(@peff.guidType, @GUID_Unknown, SizeOf(TGUID)) then Exit; |
||
1427 | |||
1428 | with TCustomInput(pvRef) do |
||
1429 | begin |
||
1430 | if peff.dwOfs<FDataFormat.dwDataSize then |
||
1431 | begin |
||
1432 | FDataFormatGUIDs[FDataFormat.dwNumObjs] := peff.guidType; |
||
1433 | |||
1434 | with FDataFormatObjects[FDataFormat.dwNumObjs] do |
||
1435 | begin |
||
1436 | pguid := @FDataFormatGUIDs[FDataFormat.dwNumObjs]; |
||
1437 | dwOfs := peff.dwOfs; |
||
1438 | dwType := peff.dwType; |
||
1439 | dwFlags := 0; |
||
1440 | end; |
||
1441 | Inc(FDataFormat.dwNumObjs); |
||
1442 | end; |
||
1443 | end; |
||
1444 | end; |
||
1445 | |||
1446 | begin |
||
1447 | Result := False; |
||
1448 | if FDevice<>nil then |
||
1449 | begin |
||
1450 | with FDataFormat do |
||
1451 | begin |
||
1452 | dwSize := SizeOf(FDataFormat); |
||
1453 | dwObjSize := SizeOf(TDIObjectDataFormat); |
||
1454 | dwNumObjs := 0; |
||
1455 | rgodf := @FDataFormatObjects; |
||
1456 | end; |
||
1457 | |||
1458 | FDevice.EnumObjects(@DIEnumDeviceObjectsProc, Self, DIDFT_ALL); |
||
1459 | if FDevice.SetDataFormat(FDataFormat)<>DI_OK then Exit; |
||
1460 | end; |
||
1461 | Result := True; |
||
1462 | end; |
||
1463 | |||
1464 | procedure TCustomInput.SetEffects(Value: TForceFeedbackEffects); |
||
1465 | begin |
||
1466 | FEffects.Assign(Value); |
||
1467 | end; |
||
1468 | |||
1469 | procedure TCustomInput.SetEnabled(Value: Boolean); |
||
1470 | begin |
||
1471 | if FEnabled<>Value then |
||
1472 | begin |
||
1473 | FEnabled := Value; |
||
1474 | if FDXInput.ComponentState*[csLoading, csReading]=[] then |
||
1475 | Initialize; |
||
1476 | end; |
||
1477 | end; |
||
1478 | |||
1479 | procedure TCustomInput.SetForceFeedback(Value: Boolean); |
||
1480 | begin |
||
1481 | if FForceFeedback<>Value then |
||
1482 | begin |
||
1483 | FForceFeedback := Value; |
||
1484 | if FDXInput.ComponentState*[csLoading, csReading]=[] then |
||
1485 | Initialize; |
||
1486 | end; |
||
1487 | end; |
||
1488 | |||
1489 | procedure TCustomInput.SetWindowHandle(Value: Integer); |
||
1490 | begin |
||
1491 | if FDevice<>nil then |
||
1492 | FDevice.SetCooperativeLevel(Value, GetCooperativeLevel); |
||
1493 | end; |
||
1494 | |||
1495 | { TKeyboard } |
||
1496 | |||
1497 | constructor TKeyboard.Create(DXInput: TCustomDXInput); |
||
1498 | begin |
||
1499 | inherited Create(DXInput); |
||
1500 | KeyAssigns := DefKeyAssign; |
||
1501 | end; |
||
1502 | |||
1503 | procedure TKeyboard.DefineProperties(Filer: TFiler); |
||
1504 | begin |
||
1505 | inherited DefineProperties(Filer); |
||
1506 | Filer.DefineBinaryProperty('Aissgns', ReadAssigns, WriteAssigns, False); |
||
1507 | Filer.DefineBinaryProperty('Assigns', ReadAssigns, WriteAssigns, True); |
||
1508 | end; |
||
1509 | |||
1510 | function TKeyboard.GetKey(Key: Integer): Boolean; |
||
1511 | begin |
||
1512 | if Key in [1..255] then |
||
1513 | Result := FKeyStates[Key] and $80<>0 |
||
1514 | else |
||
1515 | Result := False; |
||
1516 | end; |
||
1517 | |||
1518 | procedure TKeyboard.Finalize; |
||
1519 | begin |
||
1520 | FillChar(FKeyStates, SizeOf(FKeyStates), 0); |
||
1521 | inherited Finalize; |
||
1522 | end; |
||
1523 | |||
1524 | procedure TKeyboard.Initialize; |
||
1525 | begin |
||
1526 | Finalize; |
||
1527 | |||
1528 | if (not FEnabled) or (csDesigning in FDXInput.ComponentState) then Exit; |
||
1529 | |||
1530 | if FDXInput.FDInput<>nil then |
||
1531 | begin |
||
1532 | if FDXInput.FDInput.CreateDevice(GUID_SysKeyboard, FDevice, nil)<>DI_OK then Exit; |
||
1533 | FDevice.SetDataFormat(c_dfDIKeyboard); |
||
1534 | end; |
||
1535 | |||
1536 | FButtonCount := 32; |
||
1537 | |||
1538 | inherited Initialize; |
||
1539 | end; |
||
1540 | |||
1541 | procedure TKeyboard.Update; |
||
1542 | |||
1543 | function DIKEYtoVK(Key: Byte): Integer; |
||
1544 | begin |
||
1545 | Result := 0; |
||
1546 | case Key of |
||
1547 | DIK_ESCAPE : Result := VK_ESCAPE; |
||
1548 | DIK_1 : Result := Ord('1'); |
||
1549 | DIK_2 : Result := Ord('2'); |
||
1550 | DIK_3 : Result := Ord('3'); |
||
1551 | DIK_4 : Result := Ord('4'); |
||
1552 | DIK_5 : Result := Ord('5'); |
||
1553 | DIK_6 : Result := Ord('6'); |
||
1554 | DIK_7 : Result := Ord('7'); |
||
1555 | DIK_8 : Result := Ord('8'); |
||
1556 | DIK_9 : Result := Ord('9'); |
||
1557 | DIK_0 : Result := Ord('0'); |
||
1558 | DIK_EQUALS : Result := Ord('='); |
||
1559 | DIK_BACK : Result := VK_BACK; |
||
1560 | DIK_TAB : Result := VK_TAB; |
||
1561 | DIK_Q : Result := Ord('Q'); |
||
1562 | DIK_W : Result := Ord('W'); |
||
1563 | DIK_E : Result := Ord('E'); |
||
1564 | DIK_R : Result := Ord('R'); |
||
1565 | DIK_T : Result := Ord('T'); |
||
1566 | DIK_Y : Result := Ord('Y'); |
||
1567 | DIK_U : Result := Ord('U'); |
||
1568 | DIK_I : Result := Ord('I'); |
||
1569 | DIK_O : Result := Ord('O'); |
||
1570 | DIK_P : Result := Ord('P'); |
||
1571 | DIK_LBRACKET : Result := Ord('['); |
||
1572 | DIK_RBRACKET : Result := Ord(']'); |
||
1573 | DIK_RETURN : Result := VK_RETURN; |
||
1574 | DIK_LCONTROL : Result := VK_CONTROL; |
||
1575 | DIK_A : Result := Ord('A'); |
||
1576 | DIK_S : Result := Ord('S'); |
||
1577 | DIK_D : Result := Ord('D'); |
||
1578 | DIK_F : Result := Ord('F'); |
||
1579 | DIK_G : Result := Ord('G'); |
||
1580 | DIK_H : Result := Ord('H'); |
||
1581 | DIK_J : Result := Ord('J'); |
||
1582 | DIK_K : Result := Ord('K'); |
||
1583 | DIK_L : Result := Ord('L'); |
||
1584 | DIK_SEMICOLON : Result := Ord(';'); |
||
1585 | DIK_APOSTROPHE : Result := Ord(''''); |
||
1586 | DIK_LSHIFT : Result := VK_SHIFT; |
||
1587 | DIK_BACKSLASH : Result := Ord('\'); |
||
1588 | DIK_Z : Result := Ord('Z'); |
||
1589 | DIK_X : Result := Ord('X'); |
||
1590 | DIK_C : Result := Ord('C'); |
||
1591 | DIK_V : Result := Ord('V'); |
||
1592 | DIK_B : Result := Ord('B'); |
||
1593 | DIK_N : Result := Ord('N'); |
||
1594 | DIK_M : Result := Ord('M'); |
||
1595 | DIK_COMMA : Result := Ord(','); |
||
1596 | DIK_PERIOD : Result := Ord('.'); |
||
1597 | DIK_SLASH : Result := Ord('/'); |
||
1598 | DIK_RSHIFT : Result := VK_SHIFT; |
||
1599 | DIK_MULTIPLY : Result := Ord('*'); |
||
1600 | DIK_LMENU : Result := VK_MENU; |
||
1601 | DIK_SPACE : Result := VK_SPACE; |
||
1602 | DIK_CAPITAL : Result := VK_CAPITAL; |
||
1603 | DIK_F1 : Result := VK_F1; |
||
1604 | DIK_F2 : Result := VK_F2; |
||
1605 | DIK_F3 : Result := VK_F3; |
||
1606 | DIK_F4 : Result := VK_F4; |
||
1607 | DIK_F5 : Result := VK_F5; |
||
1608 | DIK_F6 : Result := VK_F6; |
||
1609 | DIK_F7 : Result := VK_F7; |
||
1610 | DIK_F8 : Result := VK_F8; |
||
1611 | DIK_F9 : Result := VK_F9; |
||
1612 | DIK_F10 : Result := VK_F10; |
||
1613 | DIK_NUMLOCK : Result := VK_NUMLOCK; |
||
1614 | DIK_SCROLL : Result := VK_SCROLL; |
||
1615 | DIK_NUMPAD7 : Result := VK_NUMPAD7; |
||
1616 | DIK_NUMPAD8 : Result := VK_NUMPAD8; |
||
1617 | DIK_NUMPAD9 : Result := VK_NUMPAD9; |
||
1618 | DIK_SUBTRACT : Result := VK_SUBTRACT; |
||
1619 | DIK_NUMPAD4 : Result := VK_NUMPAD4; |
||
1620 | DIK_NUMPAD5 : Result := VK_NUMPAD5; |
||
1621 | DIK_NUMPAD6 : Result := VK_NUMPAD6; |
||
1622 | DIK_ADD : Result := VK_ADD; |
||
1623 | DIK_NUMPAD1 : Result := VK_NUMPAD1; |
||
1624 | DIK_NUMPAD2 : Result := VK_NUMPAD2; |
||
1625 | DIK_NUMPAD3 : Result := VK_NUMPAD3; |
||
1626 | DIK_NUMPAD0 : Result := VK_NUMPAD0; |
||
1627 | DIK_DECIMAL : Result := VK_DECIMAL; |
||
1628 | DIK_F11 : Result := VK_F11; |
||
1629 | DIK_F12 : Result := VK_F12; |
||
1630 | DIK_NUMPADENTER : Result := VK_RETURN; |
||
1631 | DIK_RCONTROL : Result := VK_CONTROL; |
||
1632 | DIK_DIVIDE : Result := VK_DIVIDE; |
||
1633 | DIK_RMENU : Result := VK_MENU; |
||
1634 | DIK_HOME : Result := VK_HOME; |
||
1635 | DIK_UP : Result := VK_UP; |
||
1636 | DIK_PRIOR : Result := VK_PRIOR; |
||
1637 | DIK_LEFT : Result := VK_LEFT; |
||
1638 | DIK_RIGHT : Result := VK_RIGHT; |
||
1639 | DIK_END : Result := VK_END; |
||
1640 | DIK_DOWN : Result := VK_DOWN; |
||
1641 | DIK_NEXT : Result := VK_NEXT; |
||
1642 | DIK_INSERT : Result := VK_INSERT; |
||
1643 | DIK_DELETE : Result := VK_DELETE; |
||
1644 | DIK_LWIN : Result := VK_LWIN; |
||
1645 | DIK_RWIN : Result := VK_RWIN; |
||
1646 | DIK_APPS : Result := VK_APPS; |
||
1647 | end; |
||
1648 | end; |
||
1649 | |||
1650 | var |
||
1651 | j: Integer; |
||
1652 | i: TDXInputState; |
||
1653 | dikb: TDIKeyboardState; |
||
1654 | begin |
||
1655 | FillChar(FKeyStates, SizeOf(FKeyStates), 0); |
||
1656 | FStates := []; |
||
1657 | |||
1658 | if (not FInitialized) or FDXInput.FActiveOnly and (GetForegroundWindow<>FDXInput.FForm.Handle) then |
||
1659 | Exit; |
||
1660 | |||
1661 | if FDevice<>nil then |
||
1662 | begin |
||
1663 | FillChar(dikb, SizeOf(dikb), 0); |
||
1664 | |||
1665 | if GetDeviceState(SizeOf(dikb), dikb) then |
||
1666 | begin |
||
1667 | { The DirectInput key code is converted into the Windows virtual key code. } |
||
1668 | for j:=Low(dikb) to High(dikb) do |
||
1669 | if dikb[j] and $80<>0 then |
||
1670 | FKeyStates[Byte(DIKEYtoVK(j))] := $80; |
||
1671 | end; |
||
1672 | end else |
||
1673 | begin |
||
1674 | GetKeyboardState(FKeyStates); |
||
1675 | end; |
||
1676 | |||
1677 | for i:=LOW(TDXInputState) to HIGH(TDXInputState) do |
||
1678 | begin |
||
1679 | for j:=0 to 2 do |
||
1680 | if Keys[KeyAssigns[i, j]] then |
||
1681 | begin |
||
1682 | FStates := FStates + [i]; |
||
1683 | Break; |
||
1684 | end; |
||
1685 | end; |
||
1686 | end; |
||
1687 | |||
1688 | procedure TKeyboard.ReadAssigns(Stream: TStream); |
||
1689 | begin |
||
1690 | Stream.ReadBuffer(KeyAssigns, SizeOf(KeyAssigns)); |
||
1691 | end; |
||
1692 | |||
1693 | procedure TKeyboard.WriteAssigns(Stream: TStream); |
||
1694 | begin |
||
1695 | Stream.WriteBuffer(KeyAssigns, SizeOf(KeyAssigns)); |
||
1696 | end; |
||
1697 | |||
1698 | { TMouse } |
||
1699 | |||
1700 | constructor TMouse.Create(DXInput: TCustomDXInput); |
||
1701 | begin |
||
1702 | inherited Create(DXInput); |
||
1703 | BindInputStates := False; |
||
1704 | Enabled := False; |
||
1705 | end; |
||
1706 | |||
1707 | function TMouse.GetX: Integer; |
||
1708 | begin |
||
1709 | Result := Fdims.lX; |
||
1710 | end; |
||
1711 | |||
1712 | function TMouse.GetY: Integer; |
||
1713 | begin |
||
1714 | Result := Fdims.lY; |
||
1715 | end; |
||
1716 | |||
1717 | function TMouse.GetZ: Integer; |
||
1718 | begin |
||
1719 | Result := Fdims.lZ; |
||
1720 | end; |
||
1721 | |||
1722 | procedure TMouse.Finalize; |
||
1723 | begin |
||
1724 | FillChar(Fdims, SizeOf(Fdims), 0); |
||
1725 | inherited Finalize; |
||
1726 | end; |
||
1727 | |||
1728 | procedure TMouse.Initialize; |
||
1729 | begin |
||
1730 | Finalize; |
||
1731 | |||
1732 | if (not FEnabled) or (csDesigning in FDXInput.ComponentState) then Exit; |
||
1733 | |||
1734 | if FDXInput.FDInput<>nil then |
||
1735 | begin |
||
1736 | if FDXInput.FDInput.CreateDevice(GUID_SysMouse, FDevice, nil)<>DI_OK then Exit; |
||
1737 | FDevice.SetDataFormat(c_dfDIMouse); |
||
1738 | end else |
||
1739 | raise EDXInputError.Create(SNecessaryDirectInputUseMouse); |
||
1740 | |||
1741 | FButtonCount := 3; |
||
1742 | |||
1743 | inherited Initialize; |
||
1744 | end; |
||
1745 | |||
1746 | procedure TMouse.Update; |
||
1747 | begin |
||
1748 | FillChar(Fdims, SizeOf(Fdims), 0); |
||
1749 | FStates := []; |
||
1750 | |||
1751 | if (not FInitialized) or FDXInput.FActiveOnly and (GetForegroundWindow<>FDXInput.FForm.Handle) then |
||
1752 | Exit; |
||
1753 | |||
1754 | if FDevice<>nil then |
||
1755 | begin |
||
1756 | FillChar(Fdims, SizeOf(Fdims), 0); |
||
1757 | GetDeviceState(SizeOf(Fdims), Fdims); |
||
1758 | end; |
||
1759 | |||
1760 | if Fdims.lX<0 then FStates := FStates + [isLeft]; |
||
1761 | if Fdims.lX>0 then FStates := FStates + [isRight]; |
||
1762 | if Fdims.lY<0 then FStates := FStates + [isUp]; |
||
1763 | if Fdims.lY>0 then FStates := FStates + [isDown]; |
||
1764 | |||
1765 | if Fdims.rgbButtons[0] and $80<>0 then FStates := FStates + [isButton1]; |
||
1766 | if Fdims.rgbButtons[1] and $80<>0 then FStates := FStates + [isButton2]; |
||
1767 | if Fdims.rgbButtons[2] and $80<>0 then FStates := FStates + [isButton3]; |
||
1768 | end; |
||
1769 | |||
1770 | { TJoystick } |
||
1771 | |||
1772 | function SetDWORDProperty(pdev: IDirectInputDevice; guidProperty: PGUID; |
||
1773 | dwObject, dwHow, dwValue: DWORD): HResult; |
||
1774 | var |
||
1775 | dipdw: TDIPropDWORD; |
||
1776 | begin |
||
1777 | dipdw.diph.dwSize := SizeOf(dipdw); |
||
1778 | dipdw.diph.dwHeaderSize := SizeOf(dipdw.diph); |
||
1779 | dipdw.diph.dwObj := dwObject; |
||
1780 | dipdw.diph.dwHow := dwHow; |
||
1781 | dipdw.dwData := dwValue; |
||
1782 | |||
1783 | Result := pdev.SetProperty(guidProperty, dipdw.diph); |
||
1784 | end; |
||
1785 | |||
1786 | function SetRangeProperty(pdev: IDirectInputDevice; guidProperty: PGUID; |
||
1787 | dwObject, dwHow, Value: DWORD): HResult; |
||
1788 | var |
||
1789 | diprg: TDIPropRange; |
||
1790 | begin |
||
1791 | diprg.diph.dwSize := SizeOf(diprg); |
||
1792 | diprg.diph.dwHeaderSize := SizeOf(diprg.diph); |
||
1793 | diprg.diph.dwObj := dwObject; |
||
1794 | diprg.diph.dwHow := dwHow; |
||
1795 | diprg.lMin := -Value; |
||
1796 | diprg.lMax := +Value; |
||
1797 | |||
1798 | Result := pdev.SetProperty(guidProperty, diprg.diph); |
||
1799 | end; |
||
1800 | |||
1801 | constructor TJoystick.Create(DXInput: TCustomDXInput); |
||
1802 | begin |
||
1803 | inherited Create(DXInput); |
||
1804 | FAutoCenter := True; |
||
1805 | |||
1806 | FID := 0; |
||
1807 | |||
1808 | DeadZoneX := 50; |
||
1809 | DeadZoneY := 50; |
||
1810 | DeadZoneZ := 50; |
||
1811 | |||
1812 | RangeX := 1000; |
||
1813 | RangeY := 1000; |
||
1814 | RangeZ := 1000; |
||
1815 | end; |
||
1816 | |||
1817 | function TJoystick.GetX: Integer; |
||
1818 | begin |
||
1819 | Result := Fdijs.lX; |
||
1820 | end; |
||
1821 | |||
1822 | function TJoystick.GetY: Integer; |
||
1823 | begin |
||
1824 | Result := Fdijs.lY; |
||
1825 | end; |
||
1826 | |||
1827 | function TJoystick.GetZ: Integer; |
||
1828 | begin |
||
1829 | Result := Fdijs.lZ; |
||
1830 | end; |
||
1831 | |||
1832 | procedure TJoystick.Finalize; |
||
1833 | begin |
||
1834 | FID2 := -1; |
||
1835 | FillChar(Fdijs, SizeOf(Fdijs), 0); |
||
1836 | FillChar(FJoyCaps, SizeOf(FJoyCaps), 0); |
||
1837 | inherited Finalize; |
||
1838 | end; |
||
1839 | |||
1840 | function TJoystick.GetCooperativeLevel: Integer; |
||
1841 | begin |
||
1842 | if not FAutoCenter then |
||
1843 | Result := DISCL_EXCLUSIVE or DISCL_FOREGROUND |
||
1844 | else |
||
1845 | Result := inherited GetCooperativeLevel; |
||
1846 | end; |
||
1847 | |||
1848 | function TJoystick_EnumJoysticksCallback(const lpddi: TDIDeviceInstanceA; |
||
1849 | pvRef: Pointer): HRESULT; stdcall; |
||
1850 | begin |
||
1851 | Result := DIENUM_CONTINUE; |
||
1852 | |||
1853 | with TJoystick(pvRef) do |
||
1854 | begin |
||
1855 | if FEnumIndex=FID then |
||
1856 | begin |
||
1857 | FDeviceGUID := lpddi.guidInstance; |
||
1858 | FEnumFlag := True; |
||
1859 | Result := DIENUM_STOP; |
||
1860 | Exit; |
||
1861 | end; |
||
1862 | Inc(FEnumIndex); |
||
1863 | end; |
||
1864 | end; |
||
1865 | |||
1866 | procedure TJoystick.Initialize; |
||
1867 | var |
||
1868 | i, j: Integer; |
||
1869 | devcaps: TDIDevCaps; |
||
1870 | begin |
||
1871 | Finalize; |
||
1872 | |||
1873 | if (not FEnabled) or (FID<0) or (csDesigning in FDXInput.ComponentState) then Exit; |
||
1874 | |||
1875 | try |
||
1876 | try |
||
1877 | if FDXInput.FDInput<>nil then |
||
1878 | begin |
||
1879 | { Device search. } |
||
1880 | FEnumFlag := False; |
||
1881 | FEnumIndex := 0; |
||
1882 | |||
1883 | FDXInput.FDInput.EnumDevices(DIDEVTYPE_JOYSTICK, @TJoystick_EnumJoysticksCallback, |
||
1884 | Self, DIEDFL_ATTACHEDONLY); |
||
1885 | |||
1886 | if not FEnumFlag then Exit; |
||
1887 | |||
1888 | { Device making. } |
||
1889 | if FDXInput.FDInput.CreateDevice(FDeviceGUID, FDevice, nil)<>DI_OK then Exit; |
||
1890 | |||
1891 | devcaps.dwSize := SizeOf(devcaps); |
||
1892 | if FDevice.GetCapabilities(devcaps)=DI_OK then |
||
1893 | begin |
||
1894 | FButtonCount := devcaps.dwButtons; |
||
1895 | if devcaps.dwFlags and DIDC_FORCEFEEDBACK<>0 then |
||
1896 | FForceFeedbackDevice := True; |
||
1897 | end; |
||
1898 | |||
1899 | if FDXInput.FDInput.CreateDevice(GUID_Joystick, FDevice, nil)<>DI_OK then Exit; |
||
1900 | |||
1901 | { Device data format (TDIDataFormat) making. } |
||
1902 | |||
1903 | with FDataFormat do |
||
1904 | begin |
||
1905 | dwFlags := DIDF_ABSAXIS; |
||
1906 | dwDataSize := SizeOf(Fdijs); |
||
1907 | end; |
||
1908 | |||
1909 | if not SetDataFormat then |
||
1910 | begin |
||
1911 | FDevice := nil; |
||
1912 | Exit; |
||
1913 | end; |
||
1914 | |||
1915 | AutoCenter := FAutoCenter; |
||
1916 | |||
1917 | for i:=Low(FDeadZone) to High(FDeadZone) do |
||
1918 | SetDeadZone(i, FDeadZone[i]); |
||
1919 | |||
1920 | for i:=Low(FRange) to High(FRange) do |
||
1921 | SetRange(i, FRange[i]); |
||
1922 | |||
1923 | FDevice2 := FDevice as IDirectInputDevice2; |
||
1924 | end; |
||
1925 | except |
||
1926 | Finalize; |
||
1927 | raise; |
||
1928 | end; |
||
1929 | finally |
||
1930 | if FDevice=nil then |
||
1931 | begin |
||
1932 | { Because DirectInput cannot be used, the GetJoyPosEx function is used. } |
||
1933 | FID2 := -1; |
||
1934 | |||
1935 | j := 0; |
||
1936 | for i:=0 to 255 do |
||
1937 | begin |
||
1938 | FillChar(FJoyCaps, SizeOf(FJoyCaps), 0); |
||
1939 | if joyGetDevCaps(i, @FJoyCaps, SizeOf(FJoyCaps))=JOYERR_NOERROR then |
||
1940 | begin |
||
1941 | if FID=j then |
||
1942 | begin |
||
1943 | FID2 := i; |
||
1944 | Break; |
||
1945 | end; |
||
1946 | Inc(j); |
||
1947 | end; |
||
1948 | end; |
||
1949 | |||
1950 | if FID2<>-1 then |
||
1951 | begin |
||
1952 | if joyGetDevCaps(FID2, @FJoyCaps, SizeOf(FJoyCaps))=JOYERR_NOERROR then |
||
1953 | begin |
||
1954 | FButtonCount := FJoyCaps.wNumButtons; |
||
1955 | end else |
||
1956 | begin |
||
1957 | FID2 := -1; |
||
1958 | end; |
||
1959 | end; |
||
1960 | end; |
||
1961 | end; |
||
1962 | |||
1963 | inherited Initialize; |
||
1964 | end; |
||
1965 | |||
1966 | procedure TJoystick.SetAutoCenter(Value: Boolean); |
||
1967 | begin |
||
1968 | FAutoCenter := Value; |
||
1969 | |||
1970 | if FDevice<>nil then |
||
1971 | SetDWORDProperty(FDevice, DIPROP_AUTOCENTER, 0, DIPH_DEVICE, Ord(Value)); |
||
1972 | end; |
||
1973 | |||
1974 | procedure TJoystick.SetID(Value: Integer); |
||
1975 | begin |
||
1976 | if Value<>FID then |
||
1977 | begin |
||
1978 | FID := Value; |
||
1979 | Initialize; |
||
1980 | end; |
||
1981 | end; |
||
1982 | |||
1983 | function TJoystick.GetDeadZone(Obj: Integer): Integer; |
||
1984 | begin |
||
1985 | Result := 0; |
||
1986 | if (Obj>=Low(FDeadZone)) and (Obj<High(FDeadZone)) then |
||
1987 | Result := FDeadZone[Obj]; |
||
1988 | end; |
||
1989 | |||
1990 | function TJoystick.GetRange(Obj: Integer): Integer; |
||
1991 | begin |
||
1992 | Result := 0; |
||
1993 | if (Obj>=Low(FRange)) and (Obj<High(FRange)) then |
||
1994 | Result := FRange[Obj]; |
||
1995 | end; |
||
1996 | |||
1997 | procedure TJoystick.SetDeadZone(Obj: Integer; Value: Integer); |
||
1998 | begin |
||
1999 | if (Obj<Low(FDeadZone)) or (Obj>=High(FDeadZone)) then Exit; |
||
2000 | |||
2001 | if Value<0 then Value := 0; |
||
2002 | if Value>100 then Value := 100; |
||
2003 | |||
2004 | if Obj=Integer(@PDIJoyState2(nil).rgdwPOV[0]) then |
||
2005 | begin |
||
2006 | FDeadZone[Obj] := -1; |
||
2007 | Exit; |
||
2008 | end; |
||
2009 | |||
2010 | FDeadZone[Obj] := Value; |
||
2011 | |||
2012 | if FDevice<>nil then |
||
2013 | begin |
||
2014 | if SetDWORDProperty(FDevice, DIPROP_DEADZONE, Obj, DIPH_BYOFFSET, Value*100)<>DI_OK then |
||
2015 | FDeadZone[Obj] := -1; |
||
2016 | end; |
||
2017 | end; |
||
2018 | |||
2019 | procedure TJoystick.SetRange(Obj: Integer; Value: Integer); |
||
2020 | begin |
||
2021 | if (Obj<Low(FRange)) or (Obj>=High(FRange)) then Exit; |
||
2022 | |||
2023 | if Value<0 then Value := 0; |
||
2024 | |||
2025 | if Obj=Integer(@PDIJoyState2(nil).rgdwPOV[0]) then |
||
2026 | begin |
||
2027 | FRange[Obj] := -1; |
||
2028 | Exit; |
||
2029 | end; |
||
2030 | |||
2031 | FRange[Obj] := Value; |
||
2032 | |||
2033 | if FDevice<>nil then |
||
2034 | begin |
||
2035 | if SetRangeProperty(FDevice, DIPROP_RANGE, Obj, DIPH_BYOFFSET, Value)<>DI_OK then |
||
2036 | FRange[Obj] := -1; |
||
2037 | end; |
||
2038 | end; |
||
2039 | |||
2040 | procedure TJoystick.Update; |
||
2041 | |||
2042 | function ConvertValue(Value, wXmax, wXmin, DeadZone, Range: Integer): Integer; |
||
2043 | var |
||
2044 | c, w: Integer; |
||
2045 | begin |
||
2046 | Result := 0; |
||
2047 | |||
2048 | c := (wXmax - wXmin) div 2; |
||
2049 | Value := Value-c; |
||
2050 | |||
2051 | w := c*DeadZone div 100; |
||
2052 | c := c - w; |
||
2053 | |||
2054 | if c=0 then Exit; |
||
2055 | |||
2056 | if Abs(Value)>w then |
||
2057 | begin |
||
2058 | if Value>0 then |
||
2059 | Result := MulDiv(Value-w, Range, c) |
||
2060 | else |
||
2061 | Result := MulDiv(Value+w, Range, c); |
||
2062 | end; |
||
2063 | end; |
||
2064 | |||
2065 | var |
||
2066 | i: Integer; |
||
2067 | JoyInfo: TJoyInfoEx; |
||
2068 | begin |
||
2069 | FillChar(Fdijs, SizeOf(Fdijs), 0); |
||
2070 | FStates := []; |
||
2071 | |||
2072 | if (not FInitialized) or FDXInput.FActiveOnly and (GetForegroundWindow<>FDXInput.FForm.Handle) then |
||
2073 | Exit; |
||
2074 | |||
2075 | if FDevice<>nil then |
||
2076 | begin |
||
2077 | FDevice2.Poll; |
||
2078 | GetDeviceState(SizeOf(Fdijs), Fdijs); |
||
2079 | end else |
||
2080 | begin |
||
2081 | if FID2<>-1 then |
||
2082 | begin |
||
2083 | JoyInfo.dwSize := SizeOf(JoyInfo); |
||
2084 | JoyInfo.dwFlags := JOY_RETURNX or JOY_RETURNY or JOY_RETURNZ or JOY_RETURNPOV or |
||
2085 | JOY_RETURNBUTTONS or JOY_RETURNCENTERED; |
||
2086 | |||
2087 | joyGetPosEx(FID2, @JoyInfo); |
||
2088 | |||
2089 | with FJoyCaps do |
||
2090 | Fdijs.lX := ConvertValue(JoyInfo.wXpos, wXmax, wXmin, FDeadZone[DIJOFS_X], FRange[DIJOFS_X]); |
||
2091 | |||
2092 | with FJoyCaps do |
||
2093 | Fdijs.lY := ConvertValue(JoyInfo.wYpos, wYmax, wYmin, FDeadZone[DIJOFS_Y], FRange[DIJOFS_Y]); |
||
2094 | |||
2095 | with FJoyCaps do |
||
2096 | Fdijs.lZ := ConvertValue(JoyInfo.wZpos, wZmax, wZmin, FDeadZone[DIJOFS_Z], FRange[DIJOFS_Z]); |
||
2097 | |||
2098 | Fdijs.rgdwPOV[0] := JoyInfo.dwPOV; |
||
2099 | |||
2100 | for i:=0 to FJoyCaps.wNumButtons-1 do |
||
2101 | if JoyInfo.wButtons and (1 shl i)<>0 then |
||
2102 | Fdijs.rgbButtons[i] := $80; |
||
2103 | end; |
||
2104 | end; |
||
2105 | |||
2106 | for i:=0 to 31 do |
||
2107 | if Fdijs.rgbButtons[i] and $80<>0 then |
||
2108 | FStates := FStates + [TDXInputState(Ord(isButton1)+i)]; |
||
2109 | |||
2110 | if Fdijs.lX<0 then FStates := FStates + [isLeft]; |
||
2111 | if Fdijs.lX>0 then FStates := FStates + [isRight]; |
||
2112 | if Fdijs.lY<0 then FStates := FStates + [isUp]; |
||
2113 | if Fdijs.lY>0 then FStates := FStates + [isDown]; |
||
2114 | end; |
||
2115 | |||
2116 | { TCustomDXInput } |
||
2117 | |||
2118 | var |
||
2119 | FDirectInput: IDirectInput; |
||
2120 | FDirectInputCount: Integer; |
||
2121 | |||
2122 | procedure InitDirectInput(out DI: IDirectInput); |
||
2123 | type |
||
2124 | TDirectInputCreate = function(hinst: THandle; dwVersion: DWORD; |
||
2125 | out ppDI: IDirectInputA; punkOuter: IUnknown): HRESULT; stdcall; |
||
2126 | begin |
||
2127 | if FDirectInput=nil then |
||
2128 | begin |
||
2129 | try |
||
2130 | TDirectInputCreate(DXLoadLibrary('DInput.dll', 'DirectInputCreateA')) |
||
2131 | (HInstance, DIRECTINPUT_VERSION, FDirectInput, nil); |
||
2132 | except |
||
2133 | FDirectInput := nil; |
||
2134 | end; |
||
2135 | end; |
||
2136 | |||
2137 | DI := FDirectInput; |
||
2138 | if FDirectInput<>nil then |
||
2139 | Inc(FDirectInputCount); |
||
2140 | end; |
||
2141 | |||
2142 | procedure FinDirectInput(var DI: IDirectInput); |
||
2143 | begin |
||
2144 | if DI<>nil then |
||
2145 | begin |
||
2146 | DI := nil; |
||
2147 | Dec(FDirectInputCount); |
||
2148 | if FDirectInputCount<=0 then |
||
2149 | begin |
||
2150 | FDirectInputCount := 0; |
||
2151 | FDirectInput := nil; |
||
2152 | end; |
||
2153 | end; |
||
2154 | end; |
||
2155 | |||
2156 | constructor TCustomDXInput.Create(AOwner: TComponent); |
||
2157 | var |
||
2158 | Component: TComponent; |
||
2159 | begin |
||
2160 | inherited Create(AOwner); |
||
2161 | |||
2162 | FDevice := TList.Create; |
||
2163 | |||
2164 | FActiveOnly := True; |
||
2165 | FJoystick := TJoystick.Create(Self); |
||
2166 | FKeyboard := TKeyboard.Create(Self); |
||
2167 | FMouse := TMouse.Create(Self); |
||
2168 | FUseDirectInput := True; |
||
2169 | |||
2170 | Component := Owner; |
||
2171 | while (Component<>nil) and (not (Component is TCustomForm)) do |
||
2172 | Component := Component.Owner; |
||
2173 | if Component=nil then |
||
2174 | raise EDXInputError.CreateFmt(SNoForm, ['Owner']); |
||
2175 | FForm := TCustomForm(Component); |
||
2176 | |||
2177 | FSubClass := TControlSubClass.Create(FForm, FormWndProc); |
||
2178 | end; |
||
2179 | |||
2180 | destructor TCustomDXInput.Destroy; |
||
2181 | begin |
||
2182 | Finalize; |
||
2183 | FJoystick.Free; |
||
2184 | FKeyboard.Free; |
||
2185 | FMouse.Free; |
||
2186 | FSubClass.Free; |
||
2187 | while FDevice.Count>0 do |
||
2188 | TCustomInput(FDevice[FDevice.Count-1]).Free; |
||
2189 | FDevice.Free; |
||
2190 | inherited Destroy; |
||
2191 | end; |
||
2192 | |||
2193 | procedure TCustomDXInput.FormWndProc(var Message: TMessage; DefWindowProc: TWndMethod); |
||
2194 | |||
2195 | procedure AcquireDevice; |
||
2196 | var |
||
2197 | i: Integer; |
||
2198 | begin |
||
2199 | for i:=0 to FDevice.Count-1 do |
||
2200 | TCustomInput(FDevice[i]).Acquire; |
||
2201 | end; |
||
2202 | |||
2203 | begin |
||
2204 | case Message.Msg of |
||
2205 | WM_CREATE: |
||
2206 | begin |
||
2207 | { Window handle of Form changed. } |
||
2208 | DefWindowProc(Message); |
||
2209 | SetWindowHandle; |
||
2210 | Exit; |
||
2211 | end; |
||
2212 | WM_ACTIVATEAPP: |
||
2213 | begin |
||
2214 | DefWindowProc(Message); |
||
2215 | if TWMActivateApp(Message).Active then |
||
2216 | AcquireDevice; |
||
2217 | Exit; |
||
2218 | end; |
||
2219 | WM_ACTIVATE: |
||
2220 | begin |
||
2221 | DefWindowProc(Message); |
||
2222 | if TWMActivate(Message).Active<>WA_INACTIVE then |
||
2223 | AcquireDevice; |
||
2224 | Exit; |
||
2225 | end; |
||
2226 | end; |
||
2227 | DefWindowProc(Message); |
||
2228 | end; |
||
2229 | |||
2230 | procedure TCustomDXInput.Finalize; |
||
2231 | var |
||
2232 | i: Integer; |
||
2233 | begin |
||
2234 | for i:=0 to FDevice.Count-1 do |
||
2235 | TCustomInput(FDevice[i]).Finalize; |
||
2236 | FinDirectInput(FDInput); |
||
2237 | end; |
||
2238 | |||
2239 | procedure TCustomDXInput.Loaded; |
||
2240 | begin |
||
2241 | Initialize; |
||
2242 | end; |
||
2243 | |||
2244 | procedure TCustomDXInput.Initialize; |
||
2245 | var |
||
2246 | i: Integer; |
||
2247 | begin |
||
2248 | Finalize; |
||
2249 | if not (csDesigning in ComponentState) then |
||
2250 | begin |
||
2251 | if FUseDirectInput then InitDirectInput(FDInput); |
||
2252 | |||
2253 | for i:=0 to FDevice.Count-1 do |
||
2254 | TCustomInput(FDevice[i]).Initialize; |
||
2255 | |||
2256 | SetWindowHandle; |
||
2257 | |||
2258 | Update; |
||
2259 | end; |
||
2260 | end; |
||
2261 | |||
2262 | procedure TCustomDXInput.SetActiveOnly(Value: Boolean); |
||
2263 | begin |
||
2264 | if Value<>FActiveOnly then |
||
2265 | begin |
||
2266 | FActiveOnly := Value; |
||
2267 | if [csLoading, csReading]*ComponentState=[] then SetWindowHandle; |
||
2268 | end; |
||
2269 | end; |
||
2270 | |||
2271 | procedure TCustomDXInput.SetJoystick(Value: TJoystick); |
||
2272 | begin |
||
2273 | FJoystick.Assign(Value); |
||
2274 | end; |
||
2275 | |||
2276 | procedure TCustomDXInput.SetKeyboard(Value: TKeyboard); |
||
2277 | begin |
||
2278 | FKeyboard.Assign(Value); |
||
2279 | end; |
||
2280 | |||
2281 | procedure TCustomDXInput.SetMouse(Value: TMouse); |
||
2282 | begin |
||
2283 | FMouse.Assign(Value); |
||
2284 | end; |
||
2285 | |||
2286 | procedure TCustomDXInput.SetUseDirectInput(Value: Boolean); |
||
2287 | begin |
||
2288 | if FUseDirectInput<>Value then |
||
2289 | begin |
||
2290 | FUseDirectInput := Value; |
||
2291 | Initialize; |
||
2292 | end; |
||
2293 | end; |
||
2294 | |||
2295 | procedure TCustomDXInput.SetWindowHandle; |
||
2296 | var |
||
2297 | i: Integer; |
||
2298 | begin |
||
2299 | for i:=0 to FDevice.Count-1 do |
||
2300 | TCustomInput(FDevice[i]).SetWindowHandle(FForm.Handle); |
||
2301 | end; |
||
2302 | |||
2303 | procedure TCustomDXInput.Update; |
||
2304 | var |
||
2305 | j: Integer; |
||
2306 | i: TDXInputState; |
||
2307 | s: TDXInputStates; |
||
2308 | begin |
||
2309 | s := []; |
||
2310 | |||
2311 | for j:=0 to FDevice.Count-1 do |
||
2312 | begin |
||
2313 | TCustomInput(FDevice[j]).Update; |
||
2314 | if TCustomInput(FDevice[j]).FBindInputStates then |
||
2315 | s := s + TCustomInput(FDevice[j]).States; |
||
2316 | end; |
||
2317 | |||
2318 | for i:=Low(TDXInputState) to High(TDXInputState) do |
||
2319 | begin |
||
2320 | if (i in s) and (not (i in FOldStates)) then |
||
2321 | FStates := FStates + [i]; |
||
2322 | if (not (i in s)) and (i in FOldStates) then |
||
2323 | FStates := FStates - [i]; |
||
2324 | end; |
||
2325 | |||
2326 | FOldStates := s; |
||
2327 | end; |
||
2328 | |||
2329 | end. |